
Wenn ich das folgende Skript ausführe, wird mir die folgende Fehlermeldung angezeigt:
cp: cannot stat ls
Skriptinhalte
#!/bin/bash
#make copies of all files in directory
cd /home/don
LIST='ls'
for i in $LIST; do
ORIG=$i
DEST=$i.old
cp $ORIG $DEST
echo "Copied $i"
done
Kann jemand das Problem erkennen?
Antwort1
Einer der Hauptfehler ist, dass Sie versuchen, den ls
Befehl zu verwenden, aber die Variable LIST enthält nur die Zeichenfolge „ls“. Sie können Befehlssubstitution mit der $(command)
Syntax verwenden. Ich würde in diesem Fall davon abraten, da es Ihnen keine Informationen in dem Format liefert, das Sie leicht verwenden können. Es ist fast immer einFehler beim Parsen der Ausgabe vonls
.
In diesem Fall sollten Sie Shell Pattern Matching verwenden, auch bekannt alsGlotzen.
Ich würde stattdessen die folgende Methode in Ihrem Skript vorschlagen:
#!/bin/bash
#make copies of all files in directory
for i in /home/don/* ; do
if [[ -f $i ]]; then
orig="$i"
dest="${i}.old"
cp "$orig" "$dest"
echo "Copied $i"
else
echo "${i} is not a file"
fi
done
- Dabei wird Shell-Globbing verwendet, um alle Dateien im Verzeichnis abzugleichen.
./*
bedeutet alles im aktuellen Verzeichnis (.
). - Die
if
Anweisung prüft, ob es sich bei der Übereinstimmung um eine Datei handelt (schlägt bei Verzeichnissen und Links fehl) und führt ggf. Ihre Kopiersequenz aus. - Ich habe die Variablennamen so geändert, dass sie klein geschrieben werden, da Systemumgebungsvariablen groß geschrieben werden. So vermeiden Sie unerwünschte Namenskonflikte.
Antwort2
Nun, in Ihrem Skript ist ein kleiner Fehler. In der vierten Zeile wollten Sie ausführenlsEs sollte also nicht in einfachen Anführungszeichen stehen, sondern in das Symbol eingeschlossen werden.``. Ihr Skript ändert sich also wie folgt
LIST=`ls`
Versuchen Sie, Ihr Skript wie oben beschrieben zu aktualisieren.
Es ist jedoch ratsam, es überhaupt nicht zu verwenden $(ls)
. Sie sollten Shell-Globbing im Loop-Header bevorzugen.
for i in *; do
WieHerr David Anderssonkommentierte weiter unten, dass dies mit Anführungszeichen für variable Werte verwendet werden könnte (" $i ") für die darauf folgenden Anweisungen, da es sonst zu Problemen mit Leerzeichen in Dateinamen kommen kann. Dies kann man verhindern, indem man find in Kombination mit Prozesssubstitution verwendet:
while read l; do
i=$(basename "$l")
done < <(find . -name '*' -maxdepth 1)
Eine ausführliche Antwort mit Skript und Erklärung gibt untenHerr Arronical. Bitte beziehen Sie sich in Zukunft für bessere Skripts darauf.
Antwort3
Die 'find'-Befehlsversion
Ihr Skript kann als einzeiliger find
Befehl ausgeführt werden, ohne dass eine Analyse ls
oder das Herumhantieren mit Globs usw. erforderlich ist.
Ihr Ziel ist es, soweit die Frage lautet, Kopien aller Dateien im aktuellen Verzeichnis zu erstellen. Der entsprechende Befehl hierfür wäre:
find . -maxdepth 1 -mindepth 1 -exec cp {} {}".old" \;
Dies bewirkt, dass find
alle Dateien im .
(aktuellen) Verzeichnis bearbeitet werden und cp
für jede Datei ein Aufruf erfolgt (daher \;
). Da find
es rekursiv ist, müssen wir die Suchtiefe begrenzen, daher -maxdepth
Flag, und -mindepth
Flag soll vermeiden, .
als eines der Suchergebnisse aufgeführt zu werden.
Beispiellauf:
$ touch "file one" "file two"
$ find . -maxdepth 1 -mindepth 1 -exec cp {} {}".old" \;
$ ls -1
file one
file one.old
file two
file two.old
$
NOTIZ: cp
wird sich weiterhin über Verzeichnisse beschweren. Es gibt mehrere Möglichkeiten, damit umzugehen.
1) Sie können nur Dateien herausfiltern, wenn das Ihr Ziel ist, mit -type f
einem Flag find
wie
find . -mindepth 1 -maxdepth 1 -type f -exec cp {} {}".old" \;
2) cp -r
Auch zum Erstellen von Verzeichniskopien verwenden
find . -mindepth 1 -maxdepth 1 -exec cp -r {} {}".old" \;
Python-Einzeiler
Dies ist etwas länger als das find
andere, erledigt die Aufgabe aber immer noch und hat keine Probleme mit speziellen Dateinamen.
python -c 'import shutil; import os;[shutil.copyfile(f,f + ".old") for f in os.listdir(".") if os.path.isfile("./" + f)]'
Beispiellauf:
$ touch "test file 1" "testfile 2"
$ python -c 'import shutil;import os;[shutil.copyfile(f,f + ".old")
> for f in os.listdir(".")
> if os.path.isfile("./" + f)]'
$ ls -1
test file 1
test file 1.old
testfile 2
testfile 2.old
$
Um Verzeichnisse einzuschließen, verwenden Sieshutil.copytree(source,destination)
python -c 'import shutil; import os;[shutil.copyfile(f,f + ".old") if os.path.isfile("./" + f) else shutil.copytree(f,f + ".old") for f in os.listdir(".")]'
Beachten Sie, dass dies fehlschlägt, wenn say directory_one.old/
bereits existiert