Batch Umbenennen von Dateien mit Bash
-
03-07-2019 - |
Frage
Wie kann eine Reihe von Paketen Bash umbenennen ihre Versionsnummern entfernen? Ich habe mit beiden expr
und %%
Herumspielen, ohne Erfolg.
Beispiele:
Xft2-2.1.13.pkg
wird Xft2.pkg
jasper-1.900.1.pkg
wird jasper.pkg
xorg-libXrandr-1.2.3.pkg
wird xorg-libXrandr.pkg
Lösung
Sie können bash Parameter Expansion Funktion
verwendenfor i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done
Kurse werden benötigt für Dateinamen mit Leerzeichen.
Andere Tipps
Wenn alle Dateien im selben Verzeichnis sind die Folge
ls |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh
wird nicht Ihren Job. Die sed Befehl erstellen eine Folge von mv Befehle, die Sie dann Rohr in die Schale. Am besten ist es, zuerst die Pipeline ohne die Hinter | sh
laufen, um zu überprüfen, ob der Befehl das tut, was Sie wollen.
Um Rekursion durch mehrere Verzeichnisse verwenden so etwas wie
find . -type f |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh
Beachten Sie, dass in sed der reguläre Ausdruck Reihenfolge Gruppierung Klammern durch einen umgekehrten Schrägstrich, \(
und \)
voraus, anstatt einzelne Klammern (
und )
.
Ich werde etwas tun:
for file in *.pkg ; do
mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done
soll alle Dateien im aktuellen Verzeichnis befinden. Wenn nicht, versuchen Sie zu verwenden, wie oben von Javier beraten.
Bearbeiten . Auch diese Version verwendet keine bash-spezifische Funktionen, wie andere oben, die Sie führt zu mehr Portabilität
Hier ist ein POSIX nahezu äquivalent der derzeit Antwort akzeptiert. Dieser handelt die Bash-only ${variable/substring/replacement}
Parameter Expansion für einen, die in jedem Bourne-Shell zur Verfügung.
for i in ./*.pkg; do
mv "$i" "${i%-[0-9.]*.pkg}.pkg"
done
Der Parameter Expansion ${variable%pattern}
erzeugt den Wert von variable
mit jedem Suffix der pattern
entfernt übereinstimmt. (Es wird auch ein Präfix entfernen ${variable#pattern}
.)
Ich hielt den Unter-Pattern -[0-9.]*
von der akzeptierten Antwort, obwohl es vielleicht irreführend ist. Es ist kein regulärer Ausdruck, sondern ein glob Muster; so bedeutet dies nicht, „ein Strich, gefolgt von null oder mehr Zahlen oder Punkten“. Stattdessen bedeutet es „ein Strich, gefolgt von einer Zahl oder einem Punkt, gefolgt von irgendetwas“. Das „etwas“ wird die kürzeste mögliche Übereinstimmung, nicht die längste. (Bash bietet ##
und %%
für den längsten möglichen Präfix oder Suffix Trimmen, eher als die kürzesten.)
bessere Nutzung sed
für diese, so etwas wie:
find . -type f -name "*.pkg" |
sed -e 's/((.*)-[0-9.]*\.pkg)/\1 \2.pkg/g' |
while read nameA nameB; do
mv $nameA $nameB;
done
den regulären Ausdruck herauszufinden, wird als Übung überlassen (wie bei Dateinamen zu tun hat, die Leerzeichen enthalten)
Wir können davon ausgehen, sed
auf jedem * nichts verfügbar ist, aber wir können nicht sicher sein,
es wird sed -n
unterstützen mv Befehle zu erzeugen. (. Hinweis: Nur GNU sed
tut dies)
Auch so, bash builtins und sed, können wir schnell eine Shell-Funktion Peitsche, dies zu tun.
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls $@); do
mv -v "$file" "$(sed $sed_pattern <<< $file)"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
Verwendung
sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)|\1\2|' *.pkg
before:
./Xft2-2.1.13.pkg
./jasper-1.900.1.pkg
./xorg-libXrandr-1.2.3.pkg
after:
./Xft2.pkg
./jasper.pkg
./xorg-libXrandr.pkg
Erstellen von Zielordner:
Da mv
nicht automatisch Zielordner erstellen wir nicht verwenden können
unsere erste Version von sedrename
.
Es ist eine ziemlich kleine Änderung, so wäre es schön, diese Funktion zu übernehmen:
Wir brauchen eine Nutzenfunktion, abspath
(oder absoluten Pfad), da bash
nicht über diese Build in.
abspath () { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
Sobald wir, dass wir die Zielordner erzeugen können (e) für ein sed / umbenennen Muster, die neue Ordnerstruktur enthält.
Dadurch wird sichergestellt, wir die Namen unserer Zielordner kennen. Wenn wir Umbenennungs wir müssen es auf dem Zieldateinamen verwenden.
# generate the rename target
target="$(sed $sed_pattern <<< $file)"
# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"
# finally move the file to the target name/folders
mv -v "$file" "$target"
Hier sind die vollständigen Ordner bewusst Skript ...
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls $@); do
target="$(sed $sed_pattern <<< $file)"
mkdir -p "$(dirname $(abspath $target))"
mv -v "$file" "$target"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
Natürlich ist es immer noch funktioniert, wenn wir nicht bestimmte Zielordner haben zu.
Wenn wir alle setzen die Songs in einem Ordner gesucht, ./Beethoven/
wir können dies tun:
Verwendung
sedrename 's|Beethoven - |Beethoven/|g' *.mp3
before:
./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3
after:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
Bonusrunde ...
Dieses Skript, um Dateien von Ordnern in einen einzelnen Ordner zu verschieben:
Unter der Annahme, wir alle sammeln, die Dateien angepasst wollte, und legen Sie sie im aktuellen Ordner, können wir es tun:
sedrename 's|.*/||' **/*.mp3
before:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
after:
./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3
Hinweis auf sed regex Muster
Regelmäßige sed Musterregeln in diesem Skript anwenden, sind diese Muster nicht
PCRE (Perl Compatible Regular Expressions). Sie hätten sed
erweiterten Syntax für reguläre Ausdrücke, entweder mit oder sed -r
sed -E
je nach Plattform.
Sehen Sie die POSIX-kompatibel man re_format
für eine vollständige Beschreibung
sed Grund- und erweiterten regulären Ausdruck Muster.
Ich finde, dass Umbenennungs ist ein viel einfaches Werkzeug für diese Art der Sache zu verwenden. Ich fand es auf Homebrew für OSX
Für Ihr Beispiel, das ich tun würde:
rename 's/\d*?\.\d*?\.\d*?//' *.pkg
Die 's' bedeutet Ersatz. Die Form ist s / search / Ersatz / files_to_apply. Sie müssen Regex dafür verwenden, die eine kleine Studie dauert, aber es ist die Mühe wert.
Dies scheint, dass unter der Annahme zu arbeiten
- alles endet mit $ pkg "-"
- Ihre Version # 's immer mit einem Start
die .pkg abzustreifen, dann abzustreifen - ..
for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done
Ich hatte mehr *.txt
Dateien als .sql
in demselben Ordner umbenannt werden.
unten für mich gearbeitet:
for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done
Vielen Dank für diese Antworten. Ich hatte auch eine Art von Problem. .nzb.queued Verschieben von Dateien .nzb Dateien. Es hatte Räume und andere cruft in den Dateinamen und das mein Problem gelöst:
find . -type f -name "*.nzb.queued" |
sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\1\" \"\2.nzb\"/p" |
sh
Es basiert auf der Antwort von Diomidis Spinellis.
Die Regex erstellt eine Gruppe für die gesamten Dateinamen und eine Gruppe für den Teil vor .nzb.queued und erstellt dann einen Shell-Bewegungsbefehl. Mit den Saiten zitiert. Dies vermeidet auch eine Schleife in Shell-Skript erstellen, da diese bereits durch sed gemacht wird.