Sebuah perintah tidak mengembalikan sebuah string (ia mengembalikan kode keluar integer kecil, biasanya 0 untuk sukses dan 1 atau 2 pada kegagalan), tetapi mungkin menampilkan beberapa data, untuk dimasukkan ke dalam string.
Basile Starynkevitch
@BasileStarynkevitch ini adalah hal yang saya butuhkan.Saya perintah tahu hasil exit code.But perintah saya kode keluar selalu 0.so saya perlu untuk mengontrol output
Sebelumnya, pertanyaannya bertanya bagaimana memeriksa apakah ada file dalam direktori. Kode berikut mencapai itu, tetapi lihat jawaban rsp untuk solusi yang lebih baik.
Output kosong
Perintah tidak mengembalikan nilai - mereka mengeluarkannya. Anda dapat menangkap output ini dengan menggunakan substitusi perintah ; mis $(ls -A). Anda dapat menguji untuk string yang tidak kosong di Bash seperti ini:
if[[ $(ls -A)]];then
echo "there are files"else
echo "no files found"fi
Perhatikan bahwa saya telah menggunakan -Adaripada -a, karena menghapus entri direktori simbolik ( .) dan parent ( ..).
Catatan: Seperti yang ditunjukkan dalam komentar, substitusi perintah tidak menangkap baris baru . Oleh karena itu, jika perintah hanya menghasilkan baris baru, substitusi akan menangkap apa-apa dan tes akan kembali salah. Meskipun sangat tidak mungkin, ini dimungkinkan dalam contoh di atas, karena satu baris baru adalah nama file yang valid! Informasi lebih lanjut dalam jawaban ini .
Kode keluar
Jika Anda ingin memeriksa bahwa perintah selesai dengan sukses, Anda dapat memeriksa $?, yang berisi kode keluar dari perintah terakhir (nol untuk sukses, bukan nol untuk kegagalan). Sebagai contoh:
Metode ini memberikan false untuk perintah yang hanya menghasilkan baris baru.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
89
TL; DR
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Terima kasih kepada netj
untuk saran untuk meningkatkan sumber asli saya: if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Ini adalah pertanyaan lama tetapi saya melihat setidaknya dua hal yang perlu perbaikan atau setidaknya beberapa klarifikasi.
Masalah pertama
Masalah pertama yang saya lihat adalah bahwa sebagian besar contoh yang diberikan di sini tidak berfungsi . Mereka menggunakan perintah ls -aldan ls -Al- keduanya menghasilkan string yang tidak kosong di direktori kosong. Contoh-contoh itu selalu melaporkan bahwa ada file bahkan ketika tidak ada .
Untuk alasan itu Anda hanya perlu menggunakan ls -A- Mengapa ada orang yang ingin menggunakan -lsaklar yang berarti "menggunakan format daftar panjang" ketika semua yang Anda inginkan adalah menguji apakah ada output atau tidak, toh?
Jadi sebagian besar jawaban di sini tidak benar.
Masalah kedua
Masalah kedua adalah bahwa sementara beberapa jawaban bekerja dengan baik (orang-orang yang tidak menggunakan ls -alatau ls -Altetapi ls -Asebaliknya) mereka semua melakukan sesuatu seperti ini:
jalankan perintah
buffer seluruh output dalam RAM
mengubah output menjadi string single-line besar
bandingkan string itu dengan string kosong
Apa yang saya sarankan lakukan adalah:
jalankan perintah
hitung karakter dalam outputnya tanpa menyimpannya
atau bahkan lebih baik - hitung jumlah maksimal 1 karakter using head -c1 (terima kasih kepada netj karena memposting ide ini di komentar di bawah)
bandingkan angka itu dengan nol
Jadi misalnya, alih-alih:
if[[ $(ls -A)]]
Saya akan menggunakan:
if[[ $(ls -A | wc -c)-ne 0]]# or:if[[ $(ls -A | head -c1 | wc -c)-ne 0]]
[[ $(... | head -c | wc -c) -gt 0 ]]atau [[ -n $(... | head -c1) ]]lebih baik karena wc -charus mengkonsumsi seluruh output dari perintah.
netj
@netj Ini adalah ide yang sangat bagus. Lihat jawaban saya yang diperbarui - saya menambahkan saran Anda. Terima kasih banyak!
rsp
Ada ide tentang bagaimana mendapatkan hasil?
fahrradflucht
Saya pikir yang asli (tanpa kepala) lebih baik dalam kasus umum. Tidak selalu merupakan ide yang baik untuk mematikan perintah segera setelah mulai menulis output!
stk
@stk Sebagian besar program akan keluar dengan aman setelah menerima sinyal mematikan.
cambunctious
40
if[-z "$(ls -lA)"];then
echo "no files found"else
echo "There are files"fi
Ini akan menjalankan perintah dan memeriksa apakah output (string) yang dikembalikan memiliki panjang nol. Anda mungkin ingin memeriksa halaman manual 'test' untuk flag lainnya.
Gunakan "" di sekitar argumen yang sedang diperiksa, jika tidak, hasil kosong akan menghasilkan kesalahan sintaks karena tidak ada argumen kedua (untuk memeriksa) yang diberikan!
Catatan: yang ls -laselalu kembali .dan ..menggunakan itu tidak akan berfungsi, lihat halaman manual ls . Selain itu, walaupun ini mungkin tampak mudah dan mudah, saya kira itu akan mudah pecah. Menulis skrip / aplikasi kecil yang mengembalikan 0 atau 1 tergantung pada hasilnya jauh lebih dapat diandalkan!
Anda mungkin lebih suka menggunakan $(daripada backquote, karena $(sarang lebih baik
Basile Starynkevitch
Anda benar, itu adalah praktik yang lebih baik untuk menggunakannya selalu, meskipun kami tidak perlu bersarang di sini.
Veger
23
Bagi mereka yang menginginkan solusi elegan, versi bash-independen (sebenarnya harus bekerja di shell modern lainnya) dan mereka yang suka menggunakan one-liners untuk tugas cepat. Kita mulai!
ls | grep .&& echo 'files found'|| echo 'files not found'
(perhatikan sebagai salah satu komentar yang disebutkan, ls -aldan pada kenyataannya, hanya -ldan -asemua akan mengembalikan sesuatu, jadi dalam jawaban saya, saya menggunakan sederhanals
Jika Anda menggunakan grep -q ^sebagai gantinya, karakter baris baru juga akan cocok, dan grep tidak akan mencetak apa pun ke output standar. Selain itu, ia akan keluar segera setelah menerima input apa pun, daripada menunggu aliran inputnya berakhir.
mortehu
Harus mulai dengan ls -Ajika Anda ingin memasukkan file-file (atau direktori)
Ada -z atau -n yang tidak ada dalam parenthessis [[...]].
71GA
4
@ 71GA: Mungkin itu mudah untuk diabaikan, tetapi jika Anda akan melihat dengan seksama, Anda akan melihat bahwa itu stringadalah sinonim untuk -n string.
pengguna
10
Seperti komentar Jon Lin, ls -alakan selalu menampilkan (untuk .dan ..). Anda ingin ls -Almenghindari dua direktori ini.
Misalnya Anda bisa memasukkan output perintah ke dalam variabel shell:
v=$(ls -Al)
Notasi yang lebih tua, tidak dapat ditumpuk, adalah
v=`ls -Al`
tapi saya lebih suka notasi nestable $(...)
Anda dapat menguji apakah variabel itu tidak kosong
if[-n "$v"];then
echo there are files
else
echo no files
fi
Dan Anda bisa menggabungkan keduanya sebagai if [ -n "$(ls -Al)" ]; then
Ini tidak berfungsi: perintah lstidak pernah dijalankan. Anda hanya memeriksa apakah perluasan variabelLS tidak kosong.
gniourf_gniourf
1
@ gniourf_gniourf - apa yang membuat Anda berpikir begitu? Mantra backtick diakui tidak secantik atau sefleksibel $ (), tetapi berfungsi ...
tink
The -asaklar tidak akan pernah kembali ada konten (yaitu, itu akan kembali konten apakah ada file atau tidak) karena selalu ada implisit .dan ..hadir direktori.
mundur
3
Inilah solusi untuk kasus yang lebih ekstrem:
if[`command | head -c1 | wc -c`-gt 0];then...;fi
Ini akan bekerja
untuk semua cangkang Bourne;
jika output perintah adalah semua nol;
efisien terlepas dari ukuran output;
namun,
perintah atau subprosesnya akan dimatikan begitu ada sesuatu yang keluar.
Semua jawaban yang diberikan sejauh ini berhubungan dengan perintah yang mengakhiri dan menghasilkan string yang tidak kosong.
Sebagian besar rusak dalam pengertian berikut:
Mereka tidak berurusan dengan benar dengan perintah yang hanya menghasilkan baris baru;
mulai dari Bash≥4.4 sebagian besar spam standar akan error jika perintah menghasilkan byte nol (karena mereka menggunakan substitusi perintah);
sebagian besar akan menghirup aliran output penuh, jadi akan menunggu sampai perintah berakhir sebelum menjawab. Beberapa perintah tidak pernah berakhir (coba, misalnya, yes).
Jadi untuk memperbaiki semua masalah ini, dan untuk menjawab pertanyaan berikut secara efisien,
Bagaimana saya bisa menguji jika suatu perintah menghasilkan string kosong?
Anda juga dapat menambahkan beberapa batas waktu sehingga untuk menguji apakah perintah output string yang tidak kosong dalam waktu tertentu, menggunakan read's -tpilihan. Misalnya, untuk batas waktu 2,5 detik:
Saya pikir jawaban ini agak kurang dihargai. Saya kinerja pengujian beberapa solusi di sini menggunakan 100 iterasi untuk masing-masing 3 skenario input ( seq 1 10000000, seq 1 20, dan printf""). Satu-satunya pertarungan pendekatan baca ini tidak menang adalah dengan -z "$(command)"pendekatan untuk input kosong. Meski begitu, kerugiannya hanya sekitar 10-15%. Mereka tampaknya impas seq 1 10. Terlepas dari itu, -z "$(command)"pendekatannya menjadi sangat lambat ketika ukuran input bertambah sehingga saya menghindari menggunakannya untuk input ukuran variabel.
abathur
0
Berikut adalah pendekatan alternatif yang menulis std-out dan std-err dari beberapa perintah file sementara, dan kemudian memeriksa untuk melihat apakah file itu kosong. Manfaat dari pendekatan ini adalah bahwa ia menangkap kedua output, dan tidak menggunakan sub-shell atau pipa. Aspek-aspek terakhir ini penting karena mereka dapat mengganggu trapping bash exit handling (mis. Di sini )
tmpfile=$(mktemp)
some-command &>"$tmpfile"if[[ $?!=0]];then
echo "Command failed"elif[[-s "$tmpfile"]];then
echo "Command generated output"else
echo "Command has no output"fi
rm -f "$tmpfile"
ifne
untuk ini. joeyh.name/code/moreutilsJawaban:
Sebelumnya, pertanyaannya bertanya bagaimana memeriksa apakah ada file dalam direktori. Kode berikut mencapai itu, tetapi lihat jawaban rsp untuk solusi yang lebih baik.
Output kosong
Perintah tidak mengembalikan nilai - mereka mengeluarkannya. Anda dapat menangkap output ini dengan menggunakan substitusi perintah ; mis
$(ls -A)
. Anda dapat menguji untuk string yang tidak kosong di Bash seperti ini:Perhatikan bahwa saya telah menggunakan
-A
daripada-a
, karena menghapus entri direktori simbolik (.
) dan parent (..
).Catatan: Seperti yang ditunjukkan dalam komentar, substitusi perintah tidak menangkap baris baru . Oleh karena itu, jika perintah hanya menghasilkan baris baru, substitusi akan menangkap apa-apa dan tes akan kembali salah. Meskipun sangat tidak mungkin, ini dimungkinkan dalam contoh di atas, karena satu baris baru adalah nama file yang valid! Informasi lebih lanjut dalam jawaban ini .
Kode keluar
Jika Anda ingin memeriksa bahwa perintah selesai dengan sukses, Anda dapat memeriksa
$?
, yang berisi kode keluar dari perintah terakhir (nol untuk sukses, bukan nol untuk kegagalan). Sebagai contoh:Info lebih lanjut di sini .
sumber
-n
, jadi itu hanyaif [[ $(ls -A) ]]; then
TL; DR
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Terima kasih kepada netj untuk saran untuk meningkatkan sumber asli saya:
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Ini adalah pertanyaan lama tetapi saya melihat setidaknya dua hal yang perlu perbaikan atau setidaknya beberapa klarifikasi.
Masalah pertama
Masalah pertama yang saya lihat adalah bahwa sebagian besar contoh yang diberikan di sini tidak berfungsi . Mereka menggunakan perintah
ls -al
danls -Al
- keduanya menghasilkan string yang tidak kosong di direktori kosong. Contoh-contoh itu selalu melaporkan bahwa ada file bahkan ketika tidak ada .Untuk alasan itu Anda hanya perlu menggunakan
ls -A
- Mengapa ada orang yang ingin menggunakan-l
saklar yang berarti "menggunakan format daftar panjang" ketika semua yang Anda inginkan adalah menguji apakah ada output atau tidak, toh?Jadi sebagian besar jawaban di sini tidak benar.
Masalah kedua
Masalah kedua adalah bahwa sementara beberapa jawaban bekerja dengan baik (orang-orang yang tidak menggunakan
ls -al
atauls -Al
tetapils -A
sebaliknya) mereka semua melakukan sesuatu seperti ini:Apa yang saya sarankan lakukan adalah:
using head -c1
(terima kasih kepada netj karena memposting ide ini di komentar di bawah)
Jadi misalnya, alih-alih:
Saya akan menggunakan:
Dari pada:
Saya akan menggunakan:
dan seterusnya.
Untuk output kecil mungkin bukan masalah tetapi untuk output yang lebih besar perbedaannya mungkin signifikan:
Bandingkan dengan:
Dan bahkan lebih baik:
Contoh lengkap
Contoh yang diperbarui dari jawaban oleh Will Vousden:
Diperbarui lagi setelah saran oleh netj :
Pembaruan tambahan oleh jakeonfire :
grep
akan keluar dengan kegagalan jika tidak ada kecocokan. Kita dapat memanfaatkan ini untuk menyederhanakan sintaksis sedikit:Buang spasi putih
Jika perintah yang Anda uji bisa menghasilkan beberapa spasi putih yang ingin Anda perlakukan sebagai string kosong, maka alih-alih:
Anda bisa menggunakan:
atau dengan
head -c1
:atau semacam itu.
Ringkasan
Pertama, gunakan perintah yang berfungsi .
Kedua, hindari penyimpanan yang tidak perlu dalam RAM dan pemrosesan data yang berpotensi besar.
Jawabannya tidak menentukan bahwa output selalu kecil sehingga kemungkinan output yang besar perlu dipertimbangkan juga.
sumber
[[ $(... | head -c | wc -c) -gt 0 ]]
atau[[ -n $(... | head -c1) ]]
lebih baik karenawc -c
harus mengkonsumsi seluruh output dari perintah.Ini akan menjalankan perintah dan memeriksa apakah output (string) yang dikembalikan memiliki panjang nol. Anda mungkin ingin memeriksa halaman manual 'test' untuk flag lainnya.
Gunakan "" di sekitar argumen yang sedang diperiksa, jika tidak, hasil kosong akan menghasilkan kesalahan sintaks karena tidak ada argumen kedua (untuk memeriksa) yang diberikan!
Catatan: yang
ls -la
selalu kembali.
dan..
menggunakan itu tidak akan berfungsi, lihat halaman manual ls . Selain itu, walaupun ini mungkin tampak mudah dan mudah, saya kira itu akan mudah pecah. Menulis skrip / aplikasi kecil yang mengembalikan 0 atau 1 tergantung pada hasilnya jauh lebih dapat diandalkan!sumber
$(
daripada backquote, karena$(
sarang lebih baikBagi mereka yang menginginkan solusi elegan, versi bash-independen (sebenarnya harus bekerja di shell modern lainnya) dan mereka yang suka menggunakan one-liners untuk tugas cepat. Kita mulai!
(perhatikan sebagai salah satu komentar yang disebutkan,
ls -al
dan pada kenyataannya, hanya-l
dan-a
semua akan mengembalikan sesuatu, jadi dalam jawaban saya, saya menggunakan sederhanals
sumber
grep -q ^
sebagai gantinya, karakter baris baru juga akan cocok, dan grep tidak akan mencetak apa pun ke output standar. Selain itu, ia akan keluar segera setelah menerima input apa pun, daripada menunggu aliran inputnya berakhir.ls -A
jika Anda ingin memasukkan file-file (atau direktori)Manual Referensi Bash
6.4 Ekspresi Bersyarat Bash
Anda dapat menggunakan versi steno:
sumber
string
adalah sinonim untuk-n string
.Seperti komentar Jon Lin,
ls -al
akan selalu menampilkan (untuk.
dan..
). Anda inginls -Al
menghindari dua direktori ini.Misalnya Anda bisa memasukkan output perintah ke dalam variabel shell:
Notasi yang lebih tua, tidak dapat ditumpuk, adalah
tapi saya lebih suka notasi nestable
$(
...)
Anda dapat menguji apakah variabel itu tidak kosong
Dan Anda bisa menggabungkan keduanya sebagai
if [ -n "$(ls -Al)" ]; then
sumber
Saya kira Anda ingin output dari
ls -al
perintah, jadi dalam bash, Anda akan memiliki sesuatu seperti:sumber
ls
tidak pernah dijalankan. Anda hanya memeriksa apakah perluasan variabelLS
tidak kosong.-a
saklar tidak akan pernah kembali ada konten (yaitu, itu akan kembali konten apakah ada file atau tidak) karena selalu ada implisit.
dan..
hadir direktori.Inilah solusi untuk kasus yang lebih ekstrem:
Ini akan bekerja
namun,
sumber
Semua jawaban yang diberikan sejauh ini berhubungan dengan perintah yang mengakhiri dan menghasilkan string yang tidak kosong.
Sebagian besar rusak dalam pengertian berikut:
yes
).Jadi untuk memperbaiki semua masalah ini, dan untuk menjawab pertanyaan berikut secara efisien,
kamu bisa memakai:
Anda juga dapat menambahkan beberapa batas waktu sehingga untuk menguji apakah perintah output string yang tidak kosong dalam waktu tertentu, menggunakan
read
's-t
pilihan. Misalnya, untuk batas waktu 2,5 detik:Ucapan. Jika Anda merasa perlu menentukan apakah perintah menghasilkan string yang tidak kosong, kemungkinan besar Anda memiliki masalah XY.
sumber
seq 1 10000000
,seq 1 20
, danprintf""
). Satu-satunya pertarungan pendekatan baca ini tidak menang adalah dengan-z "$(command)"
pendekatan untuk input kosong. Meski begitu, kerugiannya hanya sekitar 10-15%. Mereka tampaknya impasseq 1 10
. Terlepas dari itu,-z "$(command)"
pendekatannya menjadi sangat lambat ketika ukuran input bertambah sehingga saya menghindari menggunakannya untuk input ukuran variabel.Berikut adalah pendekatan alternatif yang menulis std-out dan std-err dari beberapa perintah file sementara, dan kemudian memeriksa untuk melihat apakah file itu kosong. Manfaat dari pendekatan ini adalah bahwa ia menangkap kedua output, dan tidak menggunakan sub-shell atau pipa. Aspek-aspek terakhir ini penting karena mereka dapat mengganggu trapping bash exit handling (mis. Di sini )
sumber
Terkadang Anda ingin menyimpan output, jika tidak kosong, untuk meneruskannya ke perintah lain. Jika demikian, Anda bisa menggunakan sesuatu seperti
Dengan cara ini,
rm
perintah tidak akan hang jika daftar kosong.sumber