mv: cannot stat Keine solche Datei oder kein solches Verzeichnis im Shell-Skript

16

Ich habe ein Skript geschrieben, um einige Dateien von einem Ordner in einen anderen zu verschieben, aber ich habe die folgende Fehlermeldung erhalten: Ich habe 2 Ordner überprüft und festgestellt, dass für einen Ordner solche Dateien und für einen anderen Ordner keine solchen Dateien vorhanden sind, aber warum alle "mv" anzeigen kann nicht stat Keine solchen Dateien oder Verzeichnis "

    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.42.17.124_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/195.113.161.13_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.199.61.205_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.51.218.235_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/213.73.40.105_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/41.225.7.4_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/83.230.127.122_tcp.folder/data/*': No such file or directory
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/
    129.88.70.226   132.187.230.1    138.96.116.22   155.185.54.250   192.38.109.144  193.136.227.163  193.175.135.61  195.113.161.13  83.230.127.122
    130.104.72.200  132.227.62.122   147.83.29.232   156.17.10.52     192.42.43.22    193.137.173.218  193.205.215.74  212.199.61.205
    131.130.69.164  132.252.152.194  148.81.140.193  157.181.175.249  192.43.193.71   193.144.21.131   193.226.19.30   212.51.218.235
    131.188.44.102  134.151.255.180  152.66.245.162  160.78.253.31    193.1.170.136   193.145.46.243   194.199.68.165  213.73.40.105
    131.254.208.10  138.48.3.203     152.81.47.4     192.114.4.3      193.136.166.56  193.166.160.98   194.42.17.124   41.225.7.4

Das Drehbuch lautet:

    list=`ls dest_folder`
    cd dest_folder
    cwd=`pwd`
    for folder in $list;do
            mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
    done

Ich habe es reingelegt /home/esolve/project/capture/tcp_50x50/

misteryes
quelle
1
Bitte zeigen Sie die relevanten Teile des Skripts.
Mat
Ich habe meine Frage aktualisiert und das Skript hinzugefügt, danke!
misteryes
Sie benötigen ein hinzufügen , -rum die mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAmateur
Es gibt keine -rOption fürmv
Misteryes

Antworten:

24
mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Die Anführungszeichen ( ') dort verhindern, dass die Shell Globbing ausführt. Das *wird wörtlich an den mvBefehl übergeben, der fehlschlägt, da *in den angegebenen Verzeichnissen keine aufgerufenen Dateien gefunden werden .

Ändern Sie dies in:

mv "${cwd}/${folder}/data"/* "${cwd}/${folder}"

(Doppelte Anführungszeichen, um Probleme zu vermeiden, wenn Sie jemals einen Verzeichnisnamen mit Leerzeichen darin haben. *Außerhalb der Anführungszeichen.)

Sie werden trotzdem die Fehler für die leeren Verzeichnisse erhalten. (Gleicher Grund: Wenn die Datei keine Übereinstimmung mit dem Muster findet, übergibt sie das Muster selbst als Argument an den Befehl.)

Matte
quelle
Doppelte Anführungszeichen sind sinnvoll, aber warum muss ich sie *außerhalb der Anführungszeichen setzen?
Sibbs Gambling
Wenn Sie es erweitern möchten, benötigen Sie es außerhalb von @SibbsGambling
Mat
8

Es gibt verschiedene Probleme mit Ihrem Code:

list=`ls dest_folder`

Sie speichern die Ausgabe von lsZeichen ohne nachfolgende Zeilenumbrüche in $list. lsgibt die Liste der Dateinamen aus, die durch Zeilenumbrüche getrennt sind. newlineist ein beliebiges gültiges Zeichen in einem Dateinamen, sodass die Ausgabe nicht zuverlässig verwendet werden kann. Zum Beispiel der lsAusgabe für ein Verzeichnis , das enthält aund bist das gleiche wie die für ein Verzeichnis , das genannte eine Datei enthält a<newline>b.

 cd dest_folder

Sie überprüfen nicht, ob dieser Befehl fehlgeschlagen ist. Im Allgemeinen sollten Sie den Beendigungsstatus von Befehlen überprüfen. Dies gilt jedoch insbesondere cd, da bei den restlichen Befehlen davon ausgegangen wird, dass Sie sich in diesem neuen Verzeichnis befinden. Dies kann dramatische Konsequenzen haben, wenn Sie dies nicht tun.

cwd=`pwd`

POSIX-Shells behalten bereits den (einen) Pfad zum aktuellen Verzeichnis in der $PWDVariablen bei, sodass Sie ihn hier nicht verwenden müssen pwd(insbesondere im allgemeinen Fall, da durch das Ersetzen von Befehlen nachfolgende Zeilenumbrüche aus dem Pfad entfernt würden). Auch mvakzeptiert relative Pfade , damit Sie nicht den absoluten Pfad aufzubauen benötigen.

for folder in $list;do

Wenn Sie eine Variable nicht in Anführungszeichen setzen, wird der Operator split + glob in Shells verwendet. Das heißt, der Inhalt der Variablen wird aufgeteilt (auf die in $IFSmit Sonderregeln für die Leerzeichen genannten Trennzeichen ), und jedes Element, das sich aus dieser Aufteilung ergibt, wird nach Platzhalterzeichen durchsucht, damit sie in die Liste der übereinstimmenden Dateien erweitert werden können.

In diesem Fall möchten Sie die Aufteilung, jedoch nur für Zeilenumbrüche, und nicht für das Globbing. Sie müssen sie daher deaktivieren:

 IFS='
 '; set -f
 for folder in $list
   mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Eine Variable ohne Anführungszeichen zu lassen, ist wiederum der Operator split + glob . Hier möchten Sie keine, daher müssen Sie diese Variablen in Anführungszeichen setzen.

Wie bereits erwähnt, werden Platzhalter nur dann erweitert, wenn sie nicht in Anführungszeichen stehen, damit Sie diese *aus den Anführungszeichen entfernen können . Wenn Sie das Globbing früher mit deaktiviert haben set -f, müssen Sie es mit wiederherstellen, set +fbevor Sie diesen Befehl aufrufen.

Eine viel bessere Schreibweise wäre:

cd dest_folder &&
  for folder in */;do
    mv -- "${folder}data/"* "$folder"
  done

Ein paar Anmerkungen:

  • Das schließt versteckte Ordner aus und verschiebt keine versteckten Dateien aus den dataOrdnern.
  • Wir prüfen nicht, ob Dateien während des Vorgangs überschrieben werden (möglicherweise möchten Sie die -iOption hinzufügen mv).
  • Durch die Verwendung von */, sind Looping wir über Verzeichnisse nur, aber das schließt symbolische Links auf Verzeichnisse als auch. Wenn Sie dies lieber nicht möchten, müssen Sie [ -L "${folder%/}" ] && continuein der Schleife ein einfügen.
  • Wenn sich dort kein nicht versteckter Ordner befindet, */wird er zu sich selbst erweitert, sodass eine Fehlermeldung angezeigt wird mv, dass die aufgerufene Datei nicht gefunden werden kann */data/*. Wenn sich in keinem der Ordner eine nicht ausgeblendete Datei befindet, wird eine Fehlermeldung angezeigt, that-folder/data/*die nicht vorhanden ist.
Stéphane Chazelas
quelle