Es gibt verschiedene mögliche Fehlerpunkte in Ihrem Skript. Zunächst rm *.old*
wird Globbing verwendet , um eine Liste aller übereinstimmenden Dateien zu erstellen, die sich mit Dateinamen befassen können, die Leerzeichen enthalten. Ihr Skript weist jedoch jedem Ergebnis des Globs eine Variable zu und tut dies ohne Anführungszeichen. Das wird kaputt gehen, wenn Ihre Dateinamen Leerzeichen enthalten. Beispielsweise:
$ ls
'file name with spaces.old.txt' file.old.txt
$ rm *.old.* ## works: both files are deleted
$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'
Wie Sie sehen können, ist die Schleife für die Datei mit Leerzeichen im Namen fehlgeschlagen. Um es richtig zu machen, müssten Sie die Variable zitieren:
$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'
Das gleiche Problem gilt für so ziemlich jede Verwendung $i
in Ihrem Skript. Sie sollten immer Ihre Variablen zitieren .
Das nächste mögliche Problem ist, dass Sie anscheinend erwarten, dass *.old.*
Dateien mit der Erweiterung übereinstimmen .old
. Das tut es nicht. Es entspricht "0 oder mehr Zeichen" ( *
), dann a .
, dann "alt", dann einem anderen .
und dann "0 oder mehr Zeichen wieder". Dies bedeutet, dass es nicht mit so file.old
etwas wie "file.old.foo" übereinstimmt:
$ ls
file.old file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo
Also kein Matchfeind file.old
. In jedem Fall ist Ihr Skript weitaus komplexer als erforderlich. Versuchen Sie stattdessen dieses:
#!/bin/bash
for i in *; do
if [[ -f "$i" ]]; then
if [[ "$i" == *.old ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i doesn't have an .old extension"
fi
cp -v "$i" "$i".old
else
echo "$i is not a file"
fi
done
Beachten Sie, dass ich -v
die Anweisungen rm
und cp which does the same thing as what you were doing with your
echo` hinzugefügt habe.
Dies ist nicht perfekt, da beispielsweise file.old
das Skript entfernt wird und später versucht, es zu kopieren, was fehlschlägt, da die Datei nicht mehr vorhanden ist. Sie haben jedoch nicht erklärt, was Ihr Skript tatsächlich versucht, daher kann ich das nicht für Sie beheben, es sei denn, Sie sagen uns, was Sie wirklich erreichen möchten.
Wenn Sie i) alle Dateien mit der .old
Erweiterung entfernen und ii) die .old
Erweiterung zu vorhandenen Dateien hinzufügen möchten , die sie nicht haben, brauchen Sie nur:
#!/bin/bash
for i in *.old; do
if [[ -f "$i" ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i is not a file"
fi
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
if [[ -f "$i" ]]; then
## the -v makes cp report copied files
cp -v "$i" "$i".old
fi
done
rm *.old.*
, werden diese Dateien entfernt aber nicht die file.old Backup-Datei. Ich versuche das in meinem Skript zu tun. DankeDie einzigen Fälle ,
rm $oldfile
scheitern könnte, wenn der Dateiname enthält alle Zeichen vonIFS
(Leerzeichen, Tabulator, neue Zeile) oder in einem Glob - Zeichen (*
,?
,[]
).Wenn ein Zeichen von
IFS
vorhanden ist, führt die Shell eine Wortaufteilung durch und basiert auf dem Vorhandensein von Pfadnamenerweiterungen für globale Variablen in der Variablenerweiterung.Wenn der Dateiname beispielsweise lautet
foo bar.old.
,oldfile
würde die Variable enthaltenfoo bar.old.
.Wenn Sie das tun:
Shell teilt zunächst die Erweiterung des
oldfile
Raums in zwei Wörter auf,foo
undbar.old.
. So wird der Befehl:was offensichtlich zu einem unerwarteten Ergebnis führen würde. By the way, wenn Sie irgendwelche Globbing Betreiber haben (
*
,?
,[]
) in der Expansion, dann würde Pfadname Expansion zu erfolgen.Sie müssen die Variablen angeben, um das gewünschte Ergebnis zu erhalten:
Jetzt würde keine Wortteilung oder Pfadnamenerweiterung mehr durchgeführt, daher sollten Sie das gewünschte Ergebnis erhalten, dh die gewünschte Datei würde entfernt. Wenn ein Dateiname mit beginnt
-
, gehen Sie wie folgt vor :Sie könnten sich fragen, warum wir bei Verwendung im Inneren keine Variablen zitieren
[[
müssen. Der Grund dafür[[
ist einbash
Schlüsselwort, das die Variablenerweiterung intern behandelt und das Erweiterungsliteral beibehält.Nun ein paar Punkte:
Sie sollten STDERR (
exec 2>errorfile
) vor demrm
Befehl umleiten, da sonst der[[ -s errorfile ]]
Test falsch positive Ergebnisse liefern würdeSie haben verwendet
[ -s $errorfile ]
, Sie verwenden eine Variablenerweiterung$errorfile
, die NUL wäre, wenn dieerrorfile
Variable nirgendwo definiert ist. Vielleicht meinten Sie nur[ -s errorfile ]
, basierend auf der STDERR-UmleitungWenn die Variable
errorfile
definiert ist, während der Verwendung[ -s $errorfile ]
, würde es wieder ersticken oben genannten FälleIFS
und Globbing , weil im Gegensatz[[
,[
ist intern nicht behandelt durchbash
Im späteren Teil des Skripts versuchen Sie,
cp
die bereits entfernte Datei zu verwenden (erneut ohne Angabe der Variablen). Dies macht keinen Sinn. Sie sollten dieses Spannfutter überprüfen und die erforderlichen Korrekturen basierend auf Ihrem Ziel vornehmen.quelle