Bagaimana saya bisa membagi perintah shell lebih dari beberapa baris saat menggunakan pernyataan IF?

385

Bagaimana saya bisa membagi perintah ke beberapa baris di shell, ketika perintah itu merupakan bagian dari ifpernyataan?

Ini bekerja:

if ! fab --fabfile=.deploy/fabfile.py --forward-agent --disable-known-hosts deploy:$target; then rc=1                                                                       
fi

Ini tidak berfungsi:

# does not work:
if ! fab --fabfile=.deploy/fabfile.py \ 
  --forward-agent \
  --disable-known-hosts deploy:$target; then   
  rc=1
fi

Alih-alih seluruh eksekusi perintah, saya mendapatkan:

./script.sh: line 73: --forward-agent: command not found

Lebih penting lagi, apa yang hilang dari pemahaman saya tentang Bash yang akan membantu saya memahami ini dan masalah serupa di masa depan?

Dmitry Minkovsky
sumber
2
Apa kesalahannya? Saya dapat mengeksekusi $ if ! cp -n log/server1.log \ > .; then echo no copy; fitanpa kesalahan, dengan baris baru setelah\
Miserable Variable
15
Apakah Anda memiliki spasi setelah backslash terminal \ ? Mereka sangat sulit dilihat. Jika ya, Anda mungkin ingin melihat apakah Anda dapat membuat editor menghapus spasi tambahan atau membuatnya lebih terlihat.
msw
10
Ya, itu spasi setelah backslash terminal. Sama sekali. Terima kasih.
Dmitry Minkovsky
Dan ya, maaf, saya seharusnya memposting "kesalahan" (hasil yang tidak terduga)! Salahku! Editing sekarang.
Dmitry Minkovsky
Apa pengertianmu? Itu juga bukan bagian dari pertanyaan.
hakre

Jawaban:

567

Garis-kelanjutan akan gagal jika Anda memiliki spasi (spasi atau karakter tab) setelah garis miring terbalik dan sebelum baris baru. Tanpa spasi seperti itu, contoh Anda berfungsi dengan baik untuk saya:

$ cat test.sh
if ! fab --fabfile=.deploy/fabfile.py \
   --forward-agent \
   --disable-known-hosts deploy:$target; then
     echo failed
else
     echo succeeded
fi

$ alias fab=true; . ./test.sh
succeeded
$ alias fab=false; . ./test.sh
failed

Beberapa detail dipromosikan dari komentar: backslash garis-kelanjutan dalam shell sebenarnya bukan kasus khusus; itu hanyalah sebuah contoh dari aturan umum bahwa garis miring terbalik "mengutip" karakter yang langsung mengikuti, mencegah setiap perlakuan khusus yang biasanya dikenakan. Dalam hal ini, karakter berikutnya adalah baris baru, dan perlakuan khusus yang dicegah adalah menghentikan perintah. Biasanya, karakter yang dikutip akhirnya dimasukkan secara harfiah dalam perintah; baris baru backslashed malah dihapus seluruhnya. Tetapi sebaliknya, mekanismenya sama. Dan garis miring terbalik hanya mengutip karakter yang langsung mengikuti; jika karakter itu adalah spasi atau tab, Anda hanya mendapatkan spasi atau tab yang dikutip, dan baris baru berikutnya tetap tidak dikutip.

Mark Reed
sumber
5
Mark, kau tahu, aku pasti punya ruang putih. Saya bisa mereproduksi kesalahan hanya ketika menambahkan spasi putih setelah `s. For example, when adding one after the first `, saya mengerti ./soundops: line 73: --forward-agent: command not found. Masalah saya adalah saya tidak mengerti kesalahan ini. Mengapa memiliki spasi putih menghasilkan kesalahan itu? Ruang putih + \n"meniadakan" the `` dan membatasi perintah?
Dmitry Minkovsky
84
Garis miring terbalik di depan baris baru mencegah baris baru mengakhiri perintah. Tetapi sama seperti urutan pelarian khusus seperti "\ n" hanya bekerja dengan tidak ada antara backslash dan n, backslash-newline hanya bekerja dengan tidak ada apa pun antara backslash dan baris baru.
Mark Reed
19
Hahaha wow, tentu saja itu masuk akal. Tidak pernah melihatnya seperti itu. Membuka mata, namun sangat sederhana: itu hanya baris baru yang lolos. Saya benci karakter yang tidak terlihat. Mereka akan jauh lebih masuk akal bagi saya jika mereka semua hanya terlihat. Terima kasih!
Dmitry Minkovsky
7
Di sebagian besar editor, Anda dapat membuat karakter yang tidak terlihat terlihat.
lucasvc
1
Garis miring terbalik dan baris baru dihapus dari baris perintah yang efektif, tetapi spasi kosong di baris berikutnya dipertahankan. Jadi apakah itu masalah atau tidak tergantung pada apakah spasi putih akan menjadi masalah pada saat itu dalam perintah baris tunggal.
Mark Reed
52

Untuk pengguna Windows / WSL / Cygwin dll:

Pastikan bahwa akhir baris Anda hanya feed garis Unix standar, yaitu \n(LF) saja.

Menggunakan ujung baris Windows \r\n(CRLF) ujung baris akan memecah istirahat baris perintah.


Ini karena memiliki \di akhir baris dengan Windows berakhiran diterjemahkan menjadi \ \r \n.
Seperti yang dijelaskan Mark dengan benar di atas:

Garis-kelanjutan akan gagal jika Anda memiliki spasi setelah backslash dan sebelum baris baru.

Ini termasuk tidak hanya space ( ) atau tabs ( \t) tetapi juga carriage return ( \r).

Czechnology
sumber
1
Ini memperbaiki masalah yang dibuat saat membuat skrip di Windows dan kemudian menggunakannya di bash Windows (misalnya bash -c MyShellScript.sh di mana MyShellScript.sh dibuat di editor Windows). Anda harus menyimpan MyShellScript.sh dalam format UNIX mungkin menggunakan notepad ++.
BSalita