Sangat penting untuk menyadari bahwa itu sebenarnya shell yang memperluas foo*
ke daftar nama file yang cocok, jadi ada sedikit yang mv
bisa dilakukan sendiri.
Masalahnya di sini adalah bahwa ketika gumpalan tidak cocok, beberapa cangkang seperti bash
(dan kebanyakan cangkang mirip Bourne lainnya, bahwa perilaku buggy sebenarnya diperkenalkan oleh cangkang Bourne pada akhir 70-an) meneruskan pola kata demi kata ke perintah.
Jadi di sini, ketika foo*
tidak cocok dengan file apa pun, alih-alih membatalkan perintah (seperti shell pra-Bourne dan beberapa shell modern lakukan), shell melewati foo*
file kata demi kata mv
, jadi pada dasarnya meminta mv
untuk memindahkan file yang disebut foo*
.
File itu tidak ada. Jika ya, itu akan benar-benar cocok dengan polanya, jadi mv
melaporkan kesalahan. Jika polanya sudah foo[xy]
, mv
bisa saja secara tidak sengaja memindahkan file yang disebut foo[xy]
bukan foox
dan fooy
file.
Sekarang, bahkan di shell yang tidak memiliki masalah (pre-Bourne, csh, tcsh, fish, zsh, bash -O failglob), Anda masih akan mendapatkan kesalahan mv foo* ~/bar
, tetapi kali ini oleh shell.
Jika Anda ingin menganggapnya bukan kesalahan jika tidak ada file yang cocok foo*
dan dalam hal itu, tidak memindahkan apa pun, Anda ingin membuat daftar file terlebih dahulu (dengan cara yang tidak menyebabkan kesalahan seperti dengan menggunakan nullglob
opsi beberapa kerang), dan kemudian hanya panggilan mv
daftar tidak kosong.
Itu akan lebih baik daripada menyembunyikan semua kesalahan mv
(seperti menambahkan 2> /dev/null
akan) seolah-olah mv
gagal karena alasan lain, Anda mungkin masih ingin tahu mengapa.
dalam zsh
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
Atau gunakan fungsi anonim untuk menghindari penggunaan variabel sementara:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zsh
adalah salah satu dari shell yang tidak memiliki bug Bourne dan melaporkan kesalahan tanpa menjalankan perintah ketika glob tidak cocok (dan nullglob
opsi belum diaktifkan), jadi di sini, Anda bisa menyembunyikan zsh
kesalahan dan mengembalikan stderr untuk mv
jadi Anda masih akan melihat mv
kesalahan jika ada, tetapi bukan kesalahan tentang gumpalan yang tidak cocok:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Atau Anda dapat menggunakan zargs
yang juga akan menghindari masalah jika foo*
gumpalan akan berkembang menjadi terlalu banyak file.
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
Dalam ksh93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
Dalam bash:
bash
tidak memiliki sintaks untuk mengaktifkan nullglob
satu bola saja, dan failglob
opsi dibatalkan nullglob
sehingga Anda akan memerlukan hal-hal seperti:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
atau mengatur opsi dalam subkulit untuk menyimpan harus menyimpannya sebelum dan mengembalikannya sesudahnya.
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
Di yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
Di fish
Di shell ikan, perilaku nullglob adalah default untuk set
perintah, jadi itu hanya:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
Tidak ada nullglob
opsi di POSIX sh
dan tidak ada array selain dari parameter posisi. Ada trik yang dapat Anda gunakan untuk mendeteksi apakah sebuah glob cocok atau tidak:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Dengan menggunakan a foo[*]
dan foo*
glob, kita dapat membedakan antara kasus di mana tidak ada file yang cocok dan yang di mana ada satu file yang disebut foo*
(yang set -- foo*
tidak bisa dilakukan).
Lebih banyak membaca:
mv foo* ~/bar/ 2> /dev/null
?