Shell Snippets

theSplit

1998
Registriert
3 Aug. 2014
Beiträge
5.857
Hallo in die Runde,

ich würde gerne ein Sammelthema bezüglich "Shell snippets" starten, bei dem wir nützliche Skripte hier sammeln und mit anderen teilen können.
Achte bitte darauf, wenn eure Skripte etwas löschen oder erstellen und oder Rekursiv arbeiten, das dies in der Beschreibung ersichtlich ist, vor einer möglichen Ausführung!

Dann fange ich mal an mit einem Skript an:

Bash:

Funktion:
Das Skript arbeitet einen Zielordner rekursiv ab, womit ffmpeg alle Videodateien als [kw].mkv[/kw] kodiert. Ich brauche das Skript dafür, um für meinen EbookReader, mit Videowiedergabe, Videos in ein spielbares Format umzukodieren. Der Ordner der Ausgabe der Videodatei ist mit dem Inputordner identisch.

Achtung: Der Befehl löscht die Quelldateie👎 mittels [kw]rm[/kw], wenn das umkodierte Video als [kw].mkv[/kw] existiert nach der Ausführung von ffmpeg. (Zeile 14)

Das Skript sollte wie folgt aufgerufen werden: [kw]convert.sh Pfad/VideoQuellordner[/kw] mit Videoordnern/Dateien.


[src=bash]#!/bin/bash

function traverseFolders {
for entry in "$1"/*
do
if [[ -d $entry ]]; then
echo "$entry"
traverseFolders "$entry"
else
FILE=$entry
echo "Start encoding ${FILE} to ${FILE%.*}.mkv"
ffmpeg -v 0 -stats -i "$FILE" "${FILE%.*}.mkv"
if [[ "${FILE%.*}.mkv" ]]; then
rm "$FILE"
fi
fi
done
}

traverseFolders "$1"
[/src]

Update:
Hier eine verbesserte Version des Skripts.
[src="bash"]#!/bin/bash

TARGETFORMAT=".mkv"

function traverseFolders {
for entry in "$1"/*
do
if [[ -d $entry ]]; then
echo "$entry"
traverseFolders "$entry"
else
FILE=$entry
if [[ ! "${FILE%.*}$TARGETFORMAT" ]]; then
echo "Start encoding ${FILE} to ${FILE%.*}$TARGETFORMAT"
ffmpeg -v 0 -stats -i "$FILE" "${FILE%.*}$TARGETFORMAT"
if [[ "${FILE%.*}$TARGETFORMAT" ]]; then
echo "${FILE%.*}$TARGETFORMAT encoded. Removing src file."
rm "$FILE"
fi
else
echo "${FILE%.*}$TARGETFORMAT is already present. Skipping transcoding."
fi

fi
done
}

traverseFolders "$1"
[/src]
 
Zuletzt bearbeitet:
Hier ein paar `.bash_aliases` für den alltäglichen Gebrauch:
[src=bash]alias apt-pull='sudo apt update && sudo apt dist-upgrade -y'
alias lsa='ls -alh --group-directories-first'
alias borg='borg -v -p'
alias borg-latest='borg list --short --last 1'
alias df='df -h'
alias findf='find . -name'
alias git='hub'

# We use sudoers NOPASSWD option to allow usage of docker(-compose) without password
# while keeping common sudo logging.
# See https://www.projectatomic.io/blog/2015/08/why-we-dont-let-non-root-users-run-docker-in-centos-fedora-or-rhel/
# for more Info
alias docker='sudo docker'
alias docker-compose='sudo docker-compose'[/src]

Ich hab meine `.bashrc` Kommandos Applikationsweise aufgeteilt für eine bessere Übersicht, so lade ich das ganze:
[src=bash]
# Iterate over all dot files in .bash-src
# Note that we put a .bashrc-custom there for all other customizations
# Yes, it is this weird to iterate over all dot-files in a directory in bash
# Note that first line inside the loop is neccessary for the case that
# there are no matching files inside the directory
if [ -d ~/.bash-src ]; then
for file in ~/.bash-src/.[^.]*; do
[ -e "$file" ] || continue
. "$file"
done
fi
[/src]

Dieses Skript sucht in html Dateien nach dem title-tag und benennt die Dateien entsprechend um:
[src=bash]find . -name "*.html" -exec sh -c "grep -oP '(?<=<title>).*(?=<\/title>)' '{}' | xargs -I@ mv --backup=t '{}' @.html" \;[/src]

Hiermit hab ich für Dateien, die mit "step_" beginnen den String `<%= f.submit "next step"` durch `<%= f.button :submit, "next step" %>` ersetzt. Ist für Ruby on Rails gewesen, aber geht natürlich für jeden String. Das skript macht keine Änderungen an den Dateien, sondern zeigt nur an was ersetzt wird, wenn das entsprechende `inplace` flag bei sed gesetzt wird.
[src=bash]find . -name "step_*" -exec sh -c "sed 's/<%= f.submit \"next step\".*/<%= f.button :submit, \"next step\" %>/g' {} | diff -y {} - | less" \;[/src]

Bash ist so ein verdammter Clusterfuck, ich werde bei nächster Gelegenheit zu etwas wechseln bei dem ich mir nicht die Augen auskratzen will.
 
So manche MKV oder MP4 aus dem Netz sind mit Tags versehen. Ich entferne die immer ganz gerne und das kann man auf diese Weise machen:

Tags aus MKV entfernen mit mkvpropedit aus dem :

[src=bash]for file in *.mkv; do
mkvpropedit "${file}" --edit info --set title=
done[/src]

Tags aus MP4 entfernen mit MP4Box aus dem :

[src=bash]for file in *.mp4; do
MP4Box -itags all=NULL "${file}"
done[/src]

Ich würde es abspeichern als mkv.sh und mp4.sh, in die Ordner mit den mkv respkt. mp4 kopieren, ausführbar machen mit
Code:
Expand Collapse Copy
chmod +x mkv.sh
chmod +x mp4.sh
und dann ausführen mit
Code:
Expand Collapse Copy
bash mkv.sh
bash mp4.sh
 
Zuletzt bearbeitet:
Im Grunde mal die Schleife erklärt, was ja auf alle Möglichen Programme mit Parametern übertragbar, so dass der ein oder andere das auch nachbauen kann. Linux sh wohlbemerkt.

Man sucht eine Möglichkeit mehrere MKV in eine MP4 umzuwandeln ohne Neucodierung und findet im Netz diesen sinnvollen Befehl:

[src=bash]ffmpeg -i file.mkv -codec copy newfile.mp4[/src]

dann sieht der Aufbau so aus

[src=bash]for file in *.mkv; do[/src] # "for" heisst im Grunde für was für Dateien soll es gehen/für was soll er es machen, for kann man assoziieren mit für, "file" die Bezeichnung für die Datei, kann jeden Namen tragen, "*.mkv*, der Stern, das alle mkv berührt werden sollen, "; do" ist schon für den nächsten Schritt, das ausführen des Programms

[src=bash]ffmpeg -i "${file}" -codec copy "${file}".mp4"[/src] # "ffmpeg" das Programm, "-i" der erste Parameter, ""${file}"", so am besten schreiben, das bezieht sich auf den obigen selbst vergebenen Namen, "-codec copy" folgen wieder die Parameter, ""${file}.mp4"", der Output laut Befehl, und so erhalten die Dateien die Endung.mp4. Entscheiden ist hier wieder "${file}"

[src=bash]done[/src] # "done" gehört dazu, dass die Schleife auch danach endet, wenn alle mkv durchgelaufen sind.

[src=bash]for file in *.mkv; do
ffmpeg -i "${file}" -codec copy "${file}".mp4"
done[/src]

Das speichert man als Name.sh ab (wie man sie nennt bleibt einem selbst überlassen, wichtig ist .sh am Ende) und macht es mit
[src=text]chmod +x Name.sh[/src]
ausführbar. Dann kopiert man die sh ins Verzeichnis der Dateien und führt es aus mit
[src=text]bash Name.sh[/src]

Bitte korrigiert mich, wenn ich falsch liege, bzw. man es noch besser erklären kann. Dazu der Hinweis
[src=bash]for i in *.mkv; do
ffmpeg -i "${i}" -codec copy "${i}".mp4"
done[/src]
Jetzt habe ich file einfach i genannt und so sollte das auch klappen, das meine ich mit "kann jeden Namen tragen". Stimmt das?
 
  • Thread Starter Thread Starter
  • #5
[src=bash]for file in *.mkv; do[/src]

"For" und "Do" kann man so übersetzen:
[kw]Für Wert/Zeile in *.mkv; mach[/kw]

[kw]*.mkv[/kw] ist dann eine Liste (Zeilen) mit je einem Eintrag mit einer ".mkv" Datei der dann in Wert als Variable (je immer eine Zeile) gespeichert wird, damit man darauf zugreifen kann.

[src=bash]for i in *.mkv; do
ffmpeg -i "${i}" -codec copy "${i}".mp4"
done[/src]

[kw]i[/kw] kann als Variable theoretisch jeden (verfügbaren und nicht anders definierten) Namen haben. "file" und "$file" werden nur genommen, weil man mit einer Datei interagiert und das Sinn macht das Kind auch beim Namen zu nennen.
Die Anführungszeichen sind auch entsprechend wichtig, falls der Dateiname bzw. Pfad zu der Datei Leerzeichen enthält, diese werden dann entsprechend korrekt verarbeitet.

Jetzt habe ich file einfach i genannt und so sollte das auch klappen, das meine ich mit "kann jeden Namen tragen". Stimmt das?
Ja, so lange er nicht anders belegt ist und nicht wie ein Befehl heißt.

Und noch etwas, du solltest ne "Shebang"-Zeile einfügen:
[kw]#!/bin/bash[/kw]

an den Anfang der Datei, was "bash" Skripte auszeichnet.

Dann kannst du die Skripte auch mit "./name.sh" ausführen. Nach [kw]chmod +x[/kw].
 
Zuletzt bearbeitet:
Zurück
Oben