Willkommen bei Unix :)
Um einige Ihrer Nebenfragen zu beantworten, die in den Antworten auf die Hauptfrage nicht behandelt wurden:
Shell-Skripte haben sicherlich einige Ecken und Kanten, da bei Dateinamen mit Leerzeichen viele Dinge kaputt gehen. Und fast alles bricht bei Dateinamen mit Zeilenumbrüchen ab (zum Glück macht niemand diese absichtlich). Dateinamen mit Glob-Zeichen wie [
, ]
und *
sind manchmal auch ein Problem. Manchmal lohnt es sich einfach nicht, schwer lesbaren Shell-Code zu schreiben, der den Standards von Wooledges BashGuide entspricht , für den eigenen Gebrauch oder für einen einmaligen Vorgang , bei dem Sie wissen, dass Ihre Dateinamen nicht seltsam sind.
Wo soll die Variable deklariert werden?
Shell-Variablen müssen nicht deklariert werden. In Bash können Sie die shopt -o nounset
Referenz- und UnSET-Variable zu einem Fehler machen, aber das ist nicht ganz dasselbe wie nicht deklariert. Das Deaktivieren einer Variablen kann hilfreich sein. In einer Shell-Funktion empfiehlt es sich, alle Ihre Provisorien mit zu deklarieren local foo bar baz;
, damit Sie die Shell-Umgebung nicht mit Variablen verunreinigen oder, schlimmer noch, auf die gleichnamige Variable des Aufrufers treten.
Ich verstehe "Rohrleitungen" kaum.
Bei der Arbeit mit der Shell werden viele Daten übergeben, indem die Daten auf stdout gedruckt werden. Pipes senden diese Daten an ein anderes Programm, das sie auf stdin liest (und normalerweise etwas auf stdout druckt). Sie können die Ausgabe in Shell-Variablen mithilfe der Befehlssubstitution erfassen $()
. zB for i in $( locate foo | grep bar );do echo "$i"; done
. (Dies wird bei Dateinamen mit Leerzeichen unterbrochen, wie z. B. viel Shell-Code, wenn Sie nicht vorsichtig sind. Verwenden read
Sie diese Option, wenn Sie zuverlässige Skripts schreiben möchten.) locate
Druckt, grep
liest und druckt, und die Shell liest die Ausgabe von grep
. (Die Shell erhält die Ausgabe von, grep
indem sie grep mit ihrer Ausgabe startet, die mit der Eingabeseite einer von der Shell erstellten Pipe verbunden ist. Die Shell liest die Ausgabeseite der Pipe.)
Eine Pipe ist nur eine Möglichkeit für Programme, so zu arbeiten, als würden sie in eine Datei schreiben, aber tatsächlich schreiben sie in einen kleinen Puffer. Bei einem Prozess, der aus einer Pipe liest, wird der read(2)
Systemaufruf zurückgegeben, wenn Daten verfügbar sind. Dies geschieht nur, wenn etwas an das andere Ende der Pipe geschrieben wird.
Die Schale ist |
, $()
und einige andere Syntaxelemente sind , wie Sie die Schale sagen , wie die Sanitär - Verbindungsprogramme miteinander zu gründen, und an der Schale.
Es ist leicht, schlechte Redewendungen für die Shell-Programmierung zu lernen, da viele der offensichtlichen Dinge und alten Methoden versteckte Fallstricke aufweisen, die bei ungeraden Dateinamen auftreten. Siehe zum Beispiel http://mywiki.wooledge.org/BashFAQ/001 .
Es ist besser, von Anfang an sichere Methoden zum Erstellen von Skripten zu erlernen, als Methoden zu lernen, die bei ungeraden Dateinamen brechen, solange sie nicht zu klobig zum Tippen sind. :) :)
Viele GNU-Utils haben die Option -0, um ASCII NUL (das 0-Byte kann in Dateinamen oder Text nicht vorhanden sein) als Datensatztrennzeichen zu verwenden. Auf diese Weise können Sie Daten zwischen find
und sort
beispielsweise weiterleiten, ohne dass eine "Zeile" der Suchausgabe in mehrere Zeilen der Sortiereingabe umgewandelt werden kann. Dies ist nicht besonders nützlich, wenn Sie die Daten in eine Shell-Variable übertragen möchten, da bash keine Möglichkeit hat, \0
begrenzte Zeilen zu lesen . (Ich denke nicht, dass dies ein gültiger Wert für IFS ist.)
Auf jeden Fall ist es der Grund, zu vermeiden, dass die Shell Daten als Code behandelt, alles, was Sie können, immer in doppelten Anführungszeichen zu setzen, es sei denn, Sie möchten wirklich eine Wortteilung. Wenn Sie jemals möchten, dass Ihr Gehirn beim Betrachten von komplexem Shell-Code verletzt wird, schauen Sie sich einfach den Bash-Completion-Code an. (Es behandelt die programmierbare Vervollständigung, die clevere Dinge wie das Vervollständigen ls --colo => --color
oder nur das Vervollständigen von * .zip-Dateien zum Entpacken erledigt.) set -x
Und drücken Sie die Tabulatortaste: P. (Setzen Sie + x, um die Ausführungsverfolgung zu deaktivieren.)
re: your for loop: Mit *.mkv
einem Ihrer Muster haben Sie source = dest für diese Eingabedateien. ffmpeg
fordert Sie auf, die Ausgabedatei für jede Datei zu überschreiben.
Müssen Sie das Audio auch wirklich transkodieren? -c:a copy
könnte eine gute Idee sein. Die Videobitrate ist normalerweise eine größere Sache. Und Sie möchten möglicherweise -preset slow
(oder slower
sogar veryslow
) verwenden, um mehr Qualität pro Bitrate zu erzielen, und zwar auf Kosten einer höheren CPU-Auslastung. Es gibt auch -crf 20
(Standard 23). https://trac.ffmpeg.org/wiki/Encode/H.264 . Sie haben das hoffentlich schon gewusst und es -c:v libx264
weggelassen, weil es für das Bash-Scripting nicht relevant war, aber nur für den Fall ...: P ist die Standardeinstellung bei der Ausgabe auf mkv, also ist das gut.
**
Globing-Operator, mit dem rekursiv nach Dateien gesucht werden kann. Es ist nicht portabel, spielt aber gut mit der For-Loop-Syntax.