mv: can stat Brak takiego pliku lub katalogu w skrypcie powłoki

16

Napisałem skrypt, aby przenieść niektóre pliki z jednego folderu do innego, ale dostałem następujący błąd, sprawdziłem 2 foldery i zauważyłem, że w jednym folderze są takie pliki, a w innym nie ma takich plików, ale dlaczego wszystkie pokazują „mv nie można stat Brak takich plików lub katalogu ”

    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

skrypt jest:

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

Wpadłem /home/esolve/project/capture/tcp_50x50/

tajemnice
źródło
1
Pokaż odpowiednie części skryptu.
Mat
Zaktualizowałem swoje pytanie i dodałem skrypt, dzięki!
mysteryes
Czy musisz dodać -rdo mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAmateur
nie ma -ropcji dlamv
misteryes

Odpowiedzi:

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

Cytaty ( ') uniemożliwiają powłoce wykonywanie globowania. *Przekazywana jest dosłownie do mvkomendy, która nie, ponieważ nie znajdują się pliki zwane *w katalogach wskazanych.

Zmień to na:

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

(Podwójne cudzysłowy, aby zapobiec problemom, jeśli kiedykolwiek masz nazwę katalogu ze spacjami. *Poza cudzysłowami).

Nadal będziesz otrzymywać błędy dla pustych katalogów. (Taki sam powód: jeśli plik nie znajdzie dopasowania do wzorca, przekazuje sam wzorzec jako argument do polecenia).

Mata
źródło
Podwójne cytaty mają sens, ale dlaczego muszę umieszczać je *poza cytatami?
Sibbs Gambling
Jeśli chcesz go rozszerzyć, potrzebujesz go poza @SibbsGambling
Mat
8

Twój kod ma kilka problemów:

list=`ls dest_folder`

Przechowujesz wynik lsbez końcowych znaków nowego wiersza w $list. lswyświetla listę nazw plików oddzielonych znakami nowego wiersza. newlinejest tak samo poprawnym znakiem, jak każdy w nazwie pliku, więc nie można w niezawodny sposób wykorzystać danych wyjściowych. Na przykład dane lswyjściowe dla katalogu, który zawiera ai bjest taki sam, jak dla katalogu zawierającego jeden plik o nazwie a<newline>b.

 cd dest_folder

Nie sprawdzasz, czy polecenie się nie powiodło. Zasadniczo powinieneś sprawdzać status wyjścia poleceń, ale jest to szczególnie prawdziwe cd, ponieważ pozostałe polecenia zakładają, że jesteś w tym nowym katalogu, a może to mieć dramatyczne konsekwencje, gdy nie jesteś.

cwd=`pwd`

Powłoki POSIX już utrzymują (jedną) ścieżkę do bieżącego katalogu w $PWDzmiennej, więc nie powinieneś używać tego pwdtutaj (szczególnie w ogólnym przypadku, ponieważ podstawianie poleceń usuwa końcowe znaki nowej linii ze ścieżki). Również mvakceptuje ścieżki względne, więc nie trzeba budować ścieżki bezwzględnej.

for folder in $list;do

Pozostawienie zmiennej bez cudzysłowu to operator split + glob w powłokach. Oznacza to, że zawartość zmiennej jest podzielona (na separatorach wymienionych w $IFSspecjalnych regułach dla białych znaków), a każdy element wynikający z tego podziału jest szukany znaków wieloznacznych, aby można je było rozwinąć do listy pasujących plików.

Tutaj chcesz podziału, ale tylko na znaki nowego wiersza i nie chcesz globowania, więc musisz go wyłączyć:

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

Ponownie pozostawienie zmiennej niecytowanej to operator split + glob . Tutaj nie chcesz, więc musisz zacytować te zmienne.

Jak już wspomniano, symbole wieloznaczne są rozszerzane tylko wtedy, gdy nie są cytowane, abyś musiał je *usunąć z cudzysłowów. Jeśli wcześniej wyłączono globowanie za pomocą set -f, konieczne będzie przywrócenie go set +fprzed wywołaniem tego polecenia.

O wiele lepszym sposobem na napisanie tego byłoby:

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

Kilka uwag:

  • Wykluczy to ukryte foldery i nie przeniesie ukrytych plików z datafolderów.
  • Nie sprawdzamy, czy pliki nie są zastępowane w tym procesie (możesz dodać tę -iopcję mv).
  • Używając */, zapętlamy tylko katalogi , ale obejmuje to również dowiązania symboliczne do katalogów. Jeśli nie chcesz, musisz dodać [ -L "${folder%/}" ] && continuewewnątrz pętli.
  • Jeśli nie ma tam żadnego ukrytego folderu, */zostanie on rozwinięty do siebie, więc pojawi się komunikat o błędzie mvinformujący, że nie można znaleźć pliku o nazwie */data/*. Podobnie, jeśli nie ma nie ukrytego pliku w żadnym folderze, pojawi się komunikat o błędzie, that-folder/data/*który nie istnieje.
Stéphane Chazelas
źródło