mv: tidak bisa stat Tidak ada file atau direktori dalam skrip shell

16

Saya menulis sebuah skrip untuk memindahkan beberapa file dari satu folder ke folder lain, tetapi saya mendapatkan kesalahan berikut, saya memeriksa 2 folder dan melihat 1 folder ada file seperti itu dan yang lain tidak ada file seperti itu, tetapi mengapa semuanya menunjukkan "mv tidak dapat membuat stat Tidak ada file atau direktori "

    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

skripnya adalah:

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

Saya menjalankannya /home/esolve/project/capture/tcp_50x50/

Misteri
sumber
1
Tolong tunjukkan bagian yang relevan dari skrip.
Mat
Saya memperbarui pertanyaan saya dan menambahkan skrip, terima kasih!
Misteri
Apakah Anda perlu menambahkan -rke mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAmateur
tidak ada -rpilihan untukmv
misteryes

Jawaban:

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

Kutipan ( ') di sana mencegah shell dari melakukan globbing. The *sedang berlalu harfiah ke mvperintah, yang gagal karena tidak menemukan file yang disebut *dalam direktori ditunjukkan.

Ubah ini menjadi:

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

(Kutipan ganda untuk mencegah masalah jika Anda memiliki nama direktori dengan spasi di dalamnya. Di *luar tanda kutip.)

Anda masih akan mendapatkan kesalahan untuk direktori kosong. (Alasan yang sama: jika file tidak menemukan kecocokan untuk pola, itu melewati pola itu sendiri sebagai argumen ke perintah.)

Tikar
sumber
Kutipan ganda masuk akal, tetapi mengapa saya harus menempatkan di *luar tanda kutip?
Sibbs Gambling
Jika Anda ingin diperluas, Anda membutuhkannya di luar @SibbsGambling
Mat
8

Ada beberapa masalah dengan kode Anda:

list=`ls dest_folder`

Anda menyimpan output lstanpa mengekstraksi karakter baris baru $list. lsmenampilkan daftar nama file yang dipisahkan dengan karakter baris baru. newlineadalah karakter yang valid seperti halnya dalam nama file, sehingga output tidak dapat digunakan dengan andal. Misalnya lsoutput untuk direktori yang berisi adan bsama dengan yang untuk direktori yang berisi satu file yang disebut a<newline>b.

 cd dest_folder

Anda tidak memeriksa kegagalan perintah itu. Secara umum Anda harus memeriksa status keluar dari perintah, tetapi itu terutama benar cd, karena sisa perintah menganggap Anda berada di direktori baru itu, dan itu bisa memiliki konsekuensi dramatis ketika Anda tidak.

cwd=`pwd`

Shell POSIX telah mempertahankan path (satu) ke direktori saat ini dalam $PWDvariabel, jadi Anda tidak perlu menggunakan di pwdsini (terutama dalam kasus umum karena substitusi perintah akan menghapus karakter baris baru dari path). Juga, mvterima jalur relatif sehingga Anda tidak perlu membangun jalur absolut.

for folder in $list;do

Meninggalkan variabel yang tidak dikutip adalah operator split + glob di shell. Yaitu, isi dari variabel dipisah (pada separator yang disebutkan $IFSdengan aturan khusus untuk spasi putih), dan setiap elemen yang dihasilkan dari pemisahan tersebut dicari untuk karakter wildcard sehingga mereka dapat diperluas ke daftar file yang cocok.

Di sini, Anda ingin pemisahan, tetapi hanya pada karakter baris baru, dan Anda tidak ingin globbing, jadi Anda harus menonaktifkannya:

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

Sekali lagi, membiarkan variabel tidak dikutip adalah operator split + glob . Di sini, Anda tidak ingin keduanya, jadi Anda perlu mengutip variabel-variabel tersebut.

Seperti yang telah disebutkan, wildcard hanya diperluas ketika tidak dikutip, untuk itu Anda perlu *mengeluarkannya dari kutipan. Jika Anda telah menonaktifkan globbing sebelumnya set -f, Anda harus mengaktifkannya kembali set +fsebelum memanggil perintah itu.

Cara yang lebih baik untuk menulisnya adalah:

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

Beberapa catatan:

  • Itu akan mengecualikan folder tersembunyi dan tidak akan memindahkan file tersembunyi dari datafolder.
  • Kami tidak memeriksa file yang diganti dalam proses (Anda mungkin ingin menambahkan -iopsi mv).
  • Dengan menggunakan */, kami hanya beralih ke direktori , tetapi itu juga termasuk tautan simbolik ke direktori. Jika Anda tidak mau, Anda harus menambahkan [ -L "${folder%/}" ] && continuedi dalam loop.
  • Jika tidak ada folder yang tidak disembunyikan di sana */akan meluas ke dirinya sendiri, jadi Anda akan menerima pesan kesalahan dan mvmengatakan tidak dapat menemukan file yang dipanggil */data/*. Demikian pula, jika tidak ada file tidak disembunyikan di salah satu folder, Anda akan mendapatkan pesan kesalahan yang that-folder/data/*tidak ada.
Stéphane Chazelas
sumber