bash perintah multi-baris dengan komentar setelah karakter lanjutan


29

Mempertimbangkan

echo \ # this is a comment
foo

Ini memberi:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found

Setelah beberapa pencarian di web, saya menemukan solusi oleh DigitalRoss di situs saudara Stack Overflow. Jadi orang bisa melakukannya

echo `: this is a comment` \
foo

atau sebagai alternatif

echo $(: this is a comment) \
foo

Namun, DigitalRoss tidak menjelaskan mengapa solusi ini bekerja. Saya menghargai penjelasan. Dia menjawab dengan komentar:

Dulu ada gotoperintah shell yang bercabang ke label yang ditentukan seperti di :sini. The gotohilang tapi Anda masih dapat menggunakan : whateversintaks ... :adalah semacam komentar parsing sekarang.

Tapi saya ingin lebih detail dan konteks, termasuk diskusi tentang portabilitas.

Tentu saja, jika ada yang punya solusi lain, itu akan bagus juga.

Lihat juga pertanyaan sebelumnya. Bagaimana mengomentari perintah multi-baris dalam skrip shell? .


Terima pesan dari diskusi di bawah ini. Itu `: this is a comment`hanya pengganti perintah. Output dari : this is a commentapa-apa, dan itu diletakkan di tempat `: this is a comment`.

Pilihan yang lebih baik adalah sebagai berikut:

echo `# this is a comment` \
foo

Jawaban:


25

Komentar diakhiri di baris baru pertama (lihat aturan pengenalan token shell 10 ), tanpa mengizinkan baris lanjutan , jadi kode ini ada foodi baris perintah terpisah:

echo # this is a comment \
foo

Adapun proposal pertama Anda, garis miring terbalik tidak diikuti oleh baris baru, Anda hanya mengutip ruang: itu setara dengan

echo ' # this is a comment'
foo

$(: this is a comment)mengganti output dari perintah : this is a comment. Jika output dari perintah itu kosong, ini secara efektif merupakan cara yang sangat membingungkan untuk memasukkan komentar di tengah baris.

Tidak ada keajaiban yang terjadi: :adalah perintah biasa, utilitas usus besar , yang tidak melakukan apa-apa. Utilitas usus besar sebagian besar berguna ketika sintaks shell memerlukan perintah tetapi Anda tidak memiliki apa-apa untuk dilakukan.

# Sample code to compress files that don't look compressed
case "$1" in
  *.gz|*.tgz|*.bz2|*.zip|*.jar|*.od?) :;; # the file is already compressed
  *) bzip2 -9 "$1";;
esac

Kasus penggunaan lain adalah ungkapan untuk mengatur variabel jika belum ditetapkan.

: "${foo:=default value}"

Pernyataan tentang goto adalah komentar historis. Utilitas usus besar tanggal kembali bahkan sebelum shell Bourne , sampai ke shell Thompson , yang memiliki instruksi goto . Tanda titik dua berarti label; tanda titik dua adalah sintaksis yang cukup umum untuk label goto (masih ada di sed ).


Ok aku paham. Apakah ada cara lain yang lebih baik untuk memasukkan komentar dalam konteks ini yang Anda ketahui?
Faheem Mitha

3
@FaheemMitha Seperti yang direkomendasikan di utas yang Anda kutip: pisahkan perintah Anda menjadi potongan yang dapat dikelola dan komentar setiap potongan. Jika perintah Anda sangat rumit hingga membutuhkan komentar di tengah, saatnya menyederhanakannya!
Gilles 'SANGAT berhenti menjadi jahat'

1
Nah, perintah yang dimaksud memiliki banyak argumen ... Ini mengubah banyak file video menjadi satu file. Saya tidak melihat cara langsung untuk menyederhanakannya. Mungkin membuat semacam daftar, dan memberikannya sebagai argumen? Saya kira itu bisa menjadi pertanyaan lain.
Faheem Mitha

@FaheemMitha Contoh:, make_FINDskrip quickie yang membangun daftar panjang argumen find. Di sini, motivasi untuk membangun chunk by chunk adalah setiap chunk berasal dari tubuh loop, tetapi gaya yang sama memungkinkan untuk mengomentari setiap chunk.
Gilles 'SANGAT berhenti menjadi jahat'

1
Terima kasih untuk contohnya. Contoh saya pada dasarnya hanyalah daftar panjang nama yang diberikan sebagai argumen untuk suatu perintah. Saya ingin komentar terlampir pada setiap nama, karena itu adalah cara paling mudah bagi saya untuk menjaga konteks. Saya tidak melihat cara yang jelas untuk memecah perintah menjadi berkeping-keping, dan jika saya lakukan, itu bisa membuatnya lebih lama, dan itu sudah cukup lama.
Faheem Mitha

6

Anda dapat mencapai ini menggunakan array Bash, mis

#!/bin/bash
CMD=(
  echo  # this is a comment
  foo
  )

"${CMD[@]}"

Ini mendefinisikan sebuah array $CMD,, dan kemudian memperluasnya. Setelah diperluas, garis yang dihasilkan dievaluasi, sehingga dalam hal echo fooini dieksekusi.

Teks di antara (dan )mendefinisikan array dan tunduk pada sintaks bash yang biasa, jadi semuanya pada baris setelahnya #diabaikan.

Perhatikan tentang mempertahankan spasi yang dikutip

${CMD[@]}mengembang menjadi string tunggal yang merupakan gabungan dari semua elemen, dipisahkan oleh spasi. Setelah diperluas, Bash kemudian akan mengurai string menjadi token dengan cara biasa (cf $ IFS ), yang sering kali bukan yang kita inginkan.

Sebaliknya jika ekspansi dibungkus dengan tanda kutip ganda, yaitu "${CMD[@]}", maka setiap elemen dalam array dipertahankan. Pertimbangkan perbedaan antara hello world second itemdan "hello world" "second item".

Contoh ilustrasi:

# LIST=("hello world" "second item")

# for ITEM in ${LIST[@]}; do echo $ITEM; done
hello
world
second
item

# for ITEM in "${LIST[@]}"; do echo $ITEM; done
hello world
second item

Terima kasih atas jawabannya, @RobM. Jadi, saran Anda adalah memasukkan komentar / meta-informasi tentang item dalam daftar di bash array itu sendiri? Pertanyaan ini mungkin akan lebih bermanfaat jika saya menyertakan contoh jenis perintah yang saya coba gunakan. Saya tidak tahu mengapa saya tidak melakukannya.
Faheem Mitha

Bah, ternyata saya tidak membaca pertanyaan Anda dengan cermat. Kupikir kau mengajukan pertanyaan yang terhubung denganmu. Ups. :)
RobM

${CMD[@]}tidak berkembang menjadi satu string. - Mengembang ke banyak string: Tidak hanya terpecah untuk setiap elemen array, tetapi juga pada spasi putih di setiap elemen. (Yaitu: sama sekali tidak berguna)
Robert Siemer 3-15

4

Jangan lakukan $(: comment). Itu bukan komentar - itu adalah subkulit - proses shell baru untuk sebagian besar shell. Tujuan Anda adalah untuk melakukan lebih sedikit dengan input Anda, tidak lebih, yang akan dilakukan - bahkan jika itu tidak ada gunanya.

Anda bisa melakukannya ...

printf '<%s>\n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn\'t b\e any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn\'t a close \}
                $(echo the shell is looking for one >&2)
                }$(echo "}'"\" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"

}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>

Pada dasarnya apa yang terjadi di sana adalah shell melakukan substitusi. Ini menggantikan nilai parameter shell khusus $-dua kali setiap kali. Bagaimanapun juga, ini adalah string pendek, tetapi selalu disetel - dan dengan demikian substitusi dalam - yang ditafsirkan sebagai pola untuk melepaskan dari luar - tidak memperluas ke konten di antara tanda kurung ketika saya menggunakan -formulir ekspansi.

Sini:

bash -x <<""
printf %s\\n '${-##*"'${-- a set param doesn\'t expand to this optional text }'"}'

+ printf '%s\n' '${-##*"hxB"}'
${-##*"hxB"}

Lihat? Jadi itu hanya diperluas dua kali. Segera setelah shell menemukan parameter disetel semuanya di bidang ekspansi opsional dibuang, cukup banyak, dan itu mengembang ke seluruh nilainya yang dihapus dari dirinya sendiri dan tidak ada sama sekali. Dalam sebagian besar shell Anda bahkan tidak perlu melarikan diri dari kutipan, tetapi bashmembutuhkannya.

Lebih baik lagi adalah:

COMMENT=
echo      ${COMMENT-"
           this will work the same way
           but the stripping isn\'t
           necessary because, while
           the variable is set, it is also
           empty, and so it will expand to
           its value - which is nothing
           "} this you\'ll see

this you'll see
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.