Ada berbagai kemungkinan poin kegagalan dalam skrip Anda. Pertama-tama, rm *.old*
akan menggunakan globbing untuk membuat daftar semua file yang cocok, dan itu bisa berurusan dengan nama file yang mengandung spasi. Namun, skrip Anda memberikan variabel ke setiap hasil glob dan melakukannya tanpa mengutip. Itu akan rusak jika nama file Anda mengandung spasi. Sebagai contoh:
$ ls
'file name with spaces.old.txt' file.old.txt
$ rm *.old.* ## works: both files are deleted
$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'
Seperti yang Anda lihat, loop gagal untuk file dengan spasi dalam namanya. Untuk melakukannya dengan benar, Anda perlu mengutip variabel:
$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'
Masalah yang sama berlaku untuk hampir setiap penggunaan $i
dalam skrip Anda. Anda harus selalu mengutip variabel Anda .
Masalah berikutnya yang mungkin terjadi adalah Anda sepertinya mengharapkan *.old.*
file yang cocok dengan ekstensi .old
. Tidak. Ini cocok dengan "0 karakter atau lebih" ( *
), lalu a .
, lalu "lama", lalu yang lain .
dan kemudian "0 atau lebih karakter lagi". Ini berarti bahwa itu tidak akan cocok dengan sesuatu seperti file.old
, tetapi hanya sesuatu seperti `file.old.foo:
$ ls
file.old file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo
Jadi, tidak ada lawan yang cocok file.old
. Bagaimanapun, skrip Anda jauh lebih kompleks daripada yang dibutuhkan. Coba yang ini sebagai gantinya:
#!/bin/bash
for i in *; do
if [[ -f "$i" ]]; then
if [[ "$i" == *.old ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i doesn't have an .old extension"
fi
cp -v "$i" "$i".old
else
echo "$i is not a file"
fi
done
Perhatikan bahwa saya menambahkan -v
ke pernyataan rm
dan cp which does the same thing as what you were doing with your
echo`.
Ini tidak sempurna karena ketika Anda menemukan, misalnya, file.old
yang akan dihapus dan, nanti, skrip akan mencoba menyalinnya dan gagal karena file tidak ada lagi. Namun, Anda belum menjelaskan apa yang sebenarnya ingin dilakukan skrip Anda, jadi saya tidak dapat memperbaikinya kecuali Anda memberi tahu kami apa yang sebenarnya ingin Anda capai.
Jika yang Anda inginkan adalah i) menghapus semua file dengan .old
ekstensi dan ii) menambahkan .old
ekstensi ke file yang ada yang tidak memilikinya, yang Anda butuhkan adalah:
#!/bin/bash
for i in *.old; do
if [[ -f "$i" ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i is not a file"
fi
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
if [[ -f "$i" ]]; then
## the -v makes cp report copied files
cp -v "$i" "$i".old
fi
done
rm *.old.*
yang menghapus file-file ini tetapi tidak file.old file cadangan. Saya mencoba melakukan itu dalam skrip saya. Terima kasihSatu-satunya kasus
rm $oldfile
bisa gagal adalah ketika nama file Anda mengandung karakterIFS
(spasi, tab, baris baru) atau karakter gumpal (*
,?
,[]
).Jika ada karakter dari
IFS
shell akan melakukan pemisahan kata dan berdasarkan keberadaan ekspansi pathname karakter globbing pada ekspansi variabel.Jadi, misalnya, jika nama file
foo bar.old.
, variabeloldfile
akan berisifoo bar.old.
.Saat kamu melakukan:
shell pada awalnya membagi ekspansi
oldfile
pada ruang menjadi dua kata,foo
danbar.old.
. Jadi perintahnya menjadi:yang jelas akan mengarah pada hasil yang tidak terduga. By the way, jika Anda memiliki operator globbing (
*
,?
,[]
) dalam ekspansi, maka ekspansi pathname akan dilakukan juga.Anda perlu mengutip variabel untuk mendapatkan hasil yang diinginkan:
Sekarang, tidak ada pemisahan kata atau perluasan pathname yang akan dilakukan, maka Anda harus mendapatkan hasil yang diinginkan yaitu file yang diinginkan akan dihapus. Jika ada nama file yang terjadi di awal
-
, maka lakukan:Anda mungkin bertanya, mengapa kita tidak perlu mengutip variabel ketika digunakan di dalam
[[
, alasannya[[
adalahbash
kata kunci dan itu menangani ekspansi variabel secara internal menjaga ekspansi literal.Sekarang, beberapa poin:
Anda harus mengarahkan ulang STDERR (
exec 2>errorfile
) sebelumrm
perintah[[ -s errorfile ]]
tes dinyatakan akan memberikan positif palsuAnda telah menggunakan
[ -s $errorfile ]
, Anda menggunakan ekspansi variabel$errorfile
, yang akan diberikan NUL,errorfile
variabel tidak didefinisikan di mana pun. Mungkin maksud Anda, hanya[ -s errorfile ]
, berdasarkan pengalihan STDERRJika variabel
errorfile
didefinisikan, saat menggunakan[ -s $errorfile ]
, itu lagi akan tersedak kasusIFS
dan globbing yang disebutkan di atas karena tidak seperti[[
,[
tidak ditangani secara internal olehbash
Di bagian akhir skrip, Anda mencoba
cp
file yang sudah dihapus (lagi tanpa mengutip variabel), ini tidak masuk akal, Anda harus memeriksa chuck itu dan membuat koreksi yang diperlukan berdasarkan target Anda.sumber