Possiamo presumere che sed
sia disponibile su qualsiasi * nix, ma non possiamo essere sicuri che supporterà la sed -n
generazione di comandi mv. ( NOTA: solo GNU lo sed
fa.)
Anche così, bash builtins e sed, possiamo creare rapidamente una funzione di shell per farlo.
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
}
uso
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
Creazione di cartelle di destinazione:
Poiché mv
non crea automaticamente cartelle di destinazione, non possiamo utilizzare la nostra versione iniziale di sedrename
.
È un cambiamento abbastanza piccolo, quindi sarebbe bello includere questa funzionalità:
Avremo bisogno di una funzione di utilità, abspath
(o percorso assoluto) poiché bash non ha questa build.
abspath () { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
Una volta ottenuto ciò, possiamo generare le cartelle di destinazione per un pattern sed / rename che include una nuova struttura di cartelle.
Ciò garantirà che conosciamo i nomi delle nostre cartelle di destinazione. Quando rinomineremo, dovremo usarlo sul nome del file di destinazione.
# 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"
Ecco lo script completo di riconoscimento delle cartelle ...
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
}
Ovviamente funziona anche quando non abbiamo cartelle di destinazione specifiche.
Se volessimo mettere tutte le canzoni in una cartella, ./Beethoven/
possiamo farlo:
uso
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
Round bonus ...
Utilizzando questo script per spostare i file dalle cartelle in una singola cartella:
Supponendo di voler raccogliere tutti i file corrispondenti e inserirli nella cartella corrente, possiamo farlo:
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
Nota sui pattern di espressioni regolari sed
In questo script si applicano le regole dei pattern sed regolari, questi pattern non sono PCRE (Perl Compatible Regular Expressions). Potresti avere sed esteso la sintassi delle espressioni regolari, usando o sed -r
o a sed -E
seconda della tua piattaforma.
Vedere la conformità POSIX man re_format
per una descrizione completa dei pattern regexp di base ed estesi di sed.