Es gibt verschiedene Probleme mit Ihrem Skript.
for x in 'ls'
Sie durchlaufen eine Liste mit einem Wort : ls
. Sie `ls`
wollten wahrscheinlich schreiben (mit Backticks), um die Ausgabe von zu analysieren ls
. Analysieren Sie nicht die Ausgabe vonls
: Dies funktioniert nicht, wenn die Dateinamen Sonderzeichen wie Leerzeichen enthalten. Die Shell verfügt bereits über eine integrierte Methode zum Auflisten der Dateien in einem Verzeichnis: Platzhalter. Also schreibe for x in *
.
if [ ! -f $x ]; then
Dies funktioniert nicht, wenn der Dateiname Leerzeichen und andere Sonderzeichen enthält. Wenn Sie $x
externe Anführungszeichen schreiben , wird das Ergebnis in separate Wörter aufgeteilt (und jedes Wort wird zum Booten als Platzhaltermuster interpretiert). Um diesen Effekt zu vermeiden, setzen Sie $x
doppelte Anführungszeichen : if [ ! -f "$x" ]; then
. Sie können sich an komplexe Regeln erinnern oder einfach immer doppelte Anführungszeichen für Variablensubstitutionen verwenden.
Einige andere Zeilen sind aufgrund fehlender doppelter Anführungszeichen unterbrochen. Setzen Sie sie einfach um jede variable Substitution.
lc = `echo $x | tr '[A-Z]' '[a-z]'`
Dies funktioniert aufgrund der Leerzeichen um das Gleichheitszeichen nicht: Diese Zeile führt den lc
Befehl aus und übergibt ihn =
als erstes Argument (und andere Argumente). Eine Zuweisung in der Shell darf kein Leerzeichen um das =
Zeichen haben.
Sie brauchen keine Klammern um die Argumente von tr
. Hier funktioniert der Befehl zufällig, weil Sie sagen, dass Sie [
nach [
und ]
nach ]
zusätzlich zum Kleinbuchstaben ersetzen sollen .
Ich empfehle die Verwendung von Dollar-Klammern $(…)
anstelle von Backticks `…`
für die Befehlsersetzung. Sie sind äquivalent, außer dass Backticks komplexe Regeln für das Zitieren von Dingen enthalten, während $(…)
sie eine sehr intuitive Syntax haben. Alles in allem sollte dieser Befehl lauten:lc=$(echo "$x" | tr A-Z a-z)
find -name "* *" -type f | rename 's/ /-/g'
Ihre Fehlermeldung zeigt an, dass Sie den rename
Befehl aus dem util-linux-Paket haben und nicht das Perl-Skript, das unter Debian und Derivaten (einschließlich Ubuntu) gefunden wurde. Die von Ihnen verwendete Syntax ist nur mit dem Perl-Skript sinnvoll.
Wenn Sie das Perl-Skript verwenden, kann es die Groß- und Kleinschreibung in Kleinbuchstaben ändern, sodass Sie dies nicht vorher tun müssen. Und Sie müssen nicht aufrufen, es find
sei denn, Sie möchten Dateien auch in Unterverzeichnissen umbenennen (was in Ihrem ersten Teil nicht behandelt wird). Wenn Sie alle Dateien im aktuellen Verzeichnis umbenennen möchten, können Sie einfach schreiben:
prename 'tr/A-Z /a-z-/' -- *
Wenn Sie nur reguläre Dateien umbenennen möchten (jedoch keine Unterverzeichnisse, symbolischen Links usw.), verwenden Sie find
:
find . -type f -maxdepth 1 -exec prename 'tr/A-Z /a-z-/' {} +
Wenn Sie auch auf Dateien in Unterverzeichnissen reagieren möchten und die Verzeichnisnamen Leerzeichen oder Großbuchstaben enthalten können, müssen Sie darauf achten, diese in Ruhe zu lassen. Da Sie unter Linux arbeiten, können Sie mit einem Argument -execdir
aufrufen prename
, das keinen Verzeichnisnamen enthält.
find . -type f -execdir prename 'tr/A-Z /a-z-/' {} +
Was ist, wenn Sie das Perl- rename
Dienstprogramm nicht haben ? Das Dienstprogramm util-linux rename
hilft Ihnen hier nicht weiter. Sie können einen weiteren Ersatz in Ihre Schleife einfügen.
for x in ./*; do
if [ -f "$x" ]; then
y=$(echo "$x" | tr 'A-Z-' 'a-z ')
mv "$x" "$y"
fi
done
Mit bash müssen Sie nicht aufrufen tr
, sondern können die String-Substitutionskonstrukte verwenden.
for x in ./*; do
if [ -f "$x" ]; then
lc=${x,,} # convert all letters to lowercase
y=${lc// /-} # replace spaces by hyphens
if [ "$x" != "$y" ]; then
mv "$x" "$y"
fi
fi
done
Wenn Sie auch auf Dateien in Unterverzeichnissen reagieren möchten, können Sie einen rekursiven Glob verwenden (aktiviert durch die globstar
Option). Achten Sie auch hier darauf, den Verzeichnisteil in Ruhe zu lassen, wenn er Großbuchstaben oder Leerzeichen enthalten kann.
shopt -s globstar
for x in ./**/*; do
if [ -f "$x" ]; then
old_basename=${x##*/}
new_basename=${old_basename,,}
new_basename=${new_basename// /-}
if [ "$new_basename" != "$old_basename" ]; then
mv "${x%/*}/$old_basename" "${x%/*}/$new_basename"
fi
fi
done
Geben Sie in zsh autoload -U zmv
your ein .zshrc
, und Sie können das zmv
mit dem Glob-Qualifikationsmerkmal verwenden .
, um nur reguläre Dateien und Parametererweiterungskonstrukte für die Umbenennung abzugleichen:
zmv -Q '*(.)' '${(L)f// /-}'
So bearbeiten Sie auch Dateien in Unterverzeichnissen:
zmv -Qw '**/*(.)' '$1${(L)2// /-}'
mv
und wirfst einecho $lc
oder zwei ein, damit du sehen kannst, was du tust, und arbeitest dann von dort aus? Siehe auchbash -x
: tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html Das Erlernen des Fischens ist besser als nach Fisch zu fragen;)