CP-Fehler im Skript

CP-Fehler im Skript

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 lsBefehl 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 ifAnweisung 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 findBefehl ausgeführt werden, ohne dass eine Analyse lsoder 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 findalle Dateien im .(aktuellen) Verzeichnis bearbeitet werden und cpfür jede Datei ein Aufruf erfolgt (daher \;). Da findes rekursiv ist, müssen wir die Suchtiefe begrenzen, daher -maxdepthFlag, und -mindepthFlag 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: cpwird 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 feinem Flag findwie

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 findandere, 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

verwandte Informationen