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

War es hilfreich?

Lösung

Sie können bash Parameter Expansion Funktion

verwenden
for 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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top