Mengomentari dalam skrip Bash di dalam perintah multiline


164

Bagaimana saya bisa mengomentari setiap baris dari baris berikut dari skrip?

cat ${MYSQLDUMP} | \
sed '1d' | \
tr ",;" "\n" | \
sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' | \
sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' | \
sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' | \
tr "\n" "," | \
sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' | \
sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

Jika saya mencoba dan menambahkan komentar seperti:

cat ${MYSQLDUMP} | \ # Output MYSQLDUMP File

Saya mendapat:

#: not found

Apakah mungkin berkomentar di sini?


1
Nah, seperti yang Anda perhatikan, jika Anda melakukan # pertama, maka \ menjadi hanya bagian dari komentar, tetapi jika Anda melakukannya \ pertama, maka karakter selanjutnya di baris tersebut mengubah artinya dari "kelanjutan garis" menjadi "kutipan". Saya telah memikirkan satu solusi, yang diberikan di bawah ini.
DigitalRoss

Jawaban:


203

Ini akan memiliki beberapa overhead, tetapi secara teknis itu menjawab pertanyaan Anda:

echo abc `#Put your comment here` \
     def `#Another chance for a comment` \
     xyz, etc.

Dan untuk jaringan pipa secara khusus, ada solusi bersih tanpa overhead:

echo abc |        # Normal comment OK here
     tr a-z A-Z | # Another normal comment OK here
     sort |       # The pipelines are automatically continued
     uniq         # Final comment

Lihat pertanyaan Stack Overflow Cara Meletakkan Komentar Baris untuk Perintah Multi-baris .


1
Tampak agak rumit, jika tidak ada metode yang lebih sederhana?
BassKozz

1
Oke, saya telah menambahkan variasi yang sedikit lebih sederhana.
DigitalRoss

1
Bisakah Anda mengubah jawaban Anda hanya untuk menunjukkan fakta bahwa backslash tidak diperlukan sehingga saya dapat menaruh komentar di sebelah setiap baris dan hanya menggunakan pipa?
BassKozz

Saya memverifikasi bahwa versi satu dan dua berfungsi. Namun, dapatkah Anda menjelaskan mengapa mereka melakukannya dan apa yang terjadi di sini? Terima kasih.
Faheem Mitha

1
Terima kasih untuk penjelasannya. Saya telah membuka pertanyaan di unix.sx yang meminta rincian lebih lanjut, bash perintah multi-baris dengan komentar setelah karakter lanjutan .
Faheem Mitha

39

Trailing backslash harus menjadi karakter terakhir pada baris untuk ditafsirkan sebagai perintah lanjutan. Tidak ada komentar atau bahkan spasi putih diizinkan setelah itu.

Anda harus bisa meletakkan baris komentar di antara perintah Anda

# output MYSQLDUMP file
cat ${MYSQLDUMP} | \
# simplify the line
sed '/created_at/d' | \
# create some newlines
tr ",;" "\n" | \
# use some sed magic
sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' | \
# more magic
sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' | \
# even more magic
sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' | \
tr "\n" "," | \
# I hate phone numbers in my output
sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' | \ 
# one more sed call and then send it to the CSV file
sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

12
\ Tidak perlu ketika komponen perintah pipa berakhir dengan |
DigitalRoss

2
DigitalRoss, Anda benar, saya hanya bisa menggunakan pipa dan bukan backslash dan kemudian #comments saya akan bekerja dengan baik ... Anda dapat memposting itu sebagai jawaban sehingga saya bisa menerimanya.
BassKozz

8
"Anda harus dapat meletakkan baris komentar di antara perintah Anda": tidak, ini hanya berfungsi karena karakter yang ditafsirkan terakhir dari baris sebelumnya adalah |. Jika Anda mencoba cat file1\<newline>#comment<newline>file2, Anda akan melihat bahwa Anda tidak mendapatkannya cat file1 file2, tetapi sebaliknya cat file1; file2.
dubiousjim

5
Namun, seperti yang disebutkan orang lain, cat file1 | # comment<newline>sortberfungsi dengan baik. Begitu juga cat file1 && # comment<newline>echo foo. Jadi komentar dapat dimasukkan setelah |atau &&atau ||, tetapi tidak setelah `\` atau di tengah perintah.
dubiousjim

7

Seperti yang ditunjukkan DigitalRoss, garis miring terbalik tidak perlu ketika garis berakhir |. Dan Anda dapat memberi komentar pada baris berikut |:

 cat ${MYSQLDUMP} |         # Output MYSQLDUMP file
 sed '1d' |                 # skip the top line
 tr ",;" "\n" | 
 sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' |
 sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' |
 sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' |
 tr "\n" "," |
 sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' |   # hate phone numbers
 sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

5

Backslash lolos dari #, menafsirkannya sebagai karakter literalnya dan bukan karakter komentar.


3

$IFS komentar peretasan

Peretasan ini menggunakan ekspansi parameter aktif $IFS, yang digunakan untuk memisahkan kata dalam perintah:

$ echo foo${IFS}bar
foo bar

Demikian pula:

$ echo foo${IFS#comment}bar
foo bar

Dengan ini, Anda dapat memberi komentar pada baris perintah dengan lanjutan:

$ echo foo${IFS# Comment here} \
> bar
foo bar

tetapi komentar harus sebelum \kelanjutan.

Perhatikan bahwa ekspansi parameter dilakukan di dalam komentar:

$ ls file
ls: cannot access 'file': No such file or directory
$ echo foo${IFS# This command will create file: $(touch file)}bar
foo bar
$ ls file
file

Pengecualian yang jarang

Satu-satunya kasus langka yang gagal adalah jika $IFSsebelumnya dimulai dengan teks persis yang dihapus melalui ekspansi (yaitu, setelah #karakter):

$ IFS=x
$ echo foo${IFS#y}bar
foo bar
$ echo foo${IFS#x}bar
foobar

Catatan final foobartidak memiliki ruang, menggambarkan masalah ini.

Karena $IFShanya berisi ruang kosong secara default, sangat tidak mungkin Anda akan mengalami masalah ini.


Kredit untuk komentar @ PJH ini yang memicu jawaban ini.


1

Selain contoh oleh DigitalRoss, berikut adalah formulir lain yang dapat Anda gunakan jika Anda lebih suka $()backticks`

echo abc $(: comment) \
     def $(: comment) \
     xyz

Tentu saja, Anda dapat menggunakan sintaks titik dua dengan backtick juga:

echo abc `: comment` \
     def `: comment` \
     xyz

catatan tambahan

Alasannya $(#comment)tidak bekerja adalah karena setelah melihat #, memperlakukan sisa garis sebagai komentar, termasuk kurung penutup: comment). Jadi tanda kurung tidak pernah ditutup.

Backticks mem-parsing secara berbeda dan akan mendeteksi backtick penutup bahkan setelah a #.


1
Apakah itu akan membuat shell baru untuk setiap komentar?
Lonix

0

Berikut ini adalah skrip bash yang menggabungkan ide dan idiom dari beberapa komentar sebelumnya untuk memberikan, dengan contoh, komentar inline yang memiliki bentuk umum ${__+ <comment text>}.

Khususnya

  • <comment text> bisa multi-line
  • <comment text> tidak diperluas parameter
  • tidak ada subproses yang muncul (sehingga komentar efisien)

Ada satu batasan pada <comment text>, yaitu, kawat gigi '}'dan tanda kurung yang tidak seimbang ')'harus dilindungi (yaitu, '\}'dan '\)').

Ada satu persyaratan pada lingkungan bash lokal:

  • nama parameter __harus tidak disetel

Nama parameter bash lainnya yang valid secara sintaksis akan menggantikannya __ , asalkan nama tersebut tidak memiliki nilai yang ditetapkan.

Contoh skrip berikut

# provide bash inline comments having the form
#     <code> ${__+ <comment>} <code> 
#     <code> ${__+ <multiline
#                   comment>} <code>

# utility routines that obviate "useless use of cat"
function bashcat { printf '%s\n' "$(</dev/stdin)"; }
function scat { 1>&2 bashcat; exit 1; }

# ensure that '__' is unset && remains unset
[[ -z ${__+x} ]] &&  # if '__' is unset
  declare -r __ ||   # then ensure that '__' remains unset 
  scat <<EOF         # else exit with an error
Error: the parameter __='${__}' is set, hence the
  comment-idiom '\${__+ <comment text>}' will fail
EOF

${__+ (example of inline comments)
------------------------------------------------
the following inline comment-idiom is supported
    <code> ${__+ <comment>} <code> 
    <code> ${__+ <multiline
                  comment>} <code> 
(advisory) the parameter '__' must NOT be set;
  even the null declaration __='' will fail
(advisory) protect unbalanced delimiters \} and \) 
(advisory) NO parameter-expansion of <comment> 
(advisory) NO subprocesses are spawned
(advisory) a functionally equivalent idiom is 
    <code> `# <comment>` <code> 
    <code> `# <multiline
               comment>` <code>
however each comment spawns a bash subprocess
that inelegantly requires ~1ms of computation 
------------------------------------------------}
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.