Devam karakterinden sonra yorum yapan bash multi line komutu


29

Düşünmek

echo \ # this is a comment
foo

Bu verir:

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

İnternette bir arama yaptıktan sonra, DigitalRoss'un kardeş sitesi Stack Overflow'ta bir çözüm buldum . Böylece biri yapabilir

echo `: this is a comment` \
foo

Veya alternatif olarak

echo $(: this is a comment) \
foo

Ancak, DigitalRoss bu çözümlerin neden işe yaradığını açıklamamıştır. Bir açıklama için minnettar olurum. Bir yorum ile cevap verdi:

Burada gotobelirtilen etiketlere dallanmış bir kabuk komutu :vardı. gotoGitti ama yine de kullanabilirsiniz : whateversözdizimi ... :şimdi çözümlü yorumun bir tür.

Ancak taşınabilirlik tartışması da dahil olmak üzere daha fazla ayrıntı ve içerik istiyorum.

Tabii ki, başka çözümleri varsa, bu da iyi olurdu.

Ayrıca daha önceki soruya bakın Kabuk komut dosyalarında çok satırlı komutlar nasıl yorumlanır? .


Aşağıdaki tartışmadan ev mesajınızı alın. Bu `: this is a comment`sadece bir komut değişikliğidir. Çıktısı : this is a commenthiçbir şey değildir ve bunun yerine konur `: this is a comment`.

Daha iyi bir seçim şudur:

echo `# this is a comment` \
foo

Yanıtlar:


25

Yorumlar ilk satırda sona ermektedir (bkz. Kabuk belirteci tanıma kuralı 10 ), devam satırlarına izin vermeden , bu kodun fooayrı bir komut satırında olması gerekir:

echo # this is a comment \
foo

İlk teklifinize gelince, ters eğik çizgiyi yeni bir satır takip etmiyor, sadece alandan alıntı yapıyorsunuz:

echo ' # this is a comment'
foo

$(: this is a comment)komutun çıktısının yerini alır : this is a comment. Bu komutun çıktısı boşsa, bu, satırın ortasına yorum eklemek için oldukça kafa karıştırıcı bir yoldur.

Hiçbir sihir yok: :sıradan bir komut, hiçbir şey yapmadan kolon uygulaması . İki nokta üst üste yardımcı programı, kabuk sözdizimi bir komut gerektirdiğinde çoğunlukla kullanışlıdır, ancak yapacak bir işiniz olmaz.

# 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

Başka bir kullanım durumu, önceden ayarlanmadıysa bir değişkeni ayarlamak için kullanılan bir deyimdir.

: "${foo:=default value}"

Goto hakkında yorum tarihidir. Kolon yarar tarihleri bile önce gelen geri Bourne kabuğuna kadar herkese Thompson kabuğu bir vardı git talimat. Kolon daha sonra bir etiket anlamına geliyordu; iki nokta üst üste etiketler için oldukça yaygın bir sözdizimidir (hala sed'de bulunur ).


Tamam anladım. Bu bağlamda, sizin bildiğiniz yorumları eklemenin daha iyi bir yolu var mı?
Faheem Mitha

3
@FaheemMitha Alıntı yaptığınız iş parçacığında önerildiği gibi: komutunuzu yönetilebilir parçalara ayırın ve her gruba yorum yapın. Eğer emriniz ortada bir yoruma ihtiyaç duyacak kadar karmaşıksa, basitleştirmenin zamanı geldi!
Gilles 'SO- kötülük' dur '21

1
Eh, söz konusu komutun birçok tartışması var ... Bir sürü video dosyasını tek bir dosyaya dönüştürüyor. Basitleştirmek için doğrudan bir yol görmüyorum. Belki bir tür liste oluşturabilir ve onu argüman olarak iletebilirsin? Sanırım bu başka bir soru olabilir.
Faheem Mitha

@FaheemMitha Örnek: make_FINDuzun bir argüman listesi oluşturan hızlı bir komut dosyası find. Burada, chunk tarafından chunk oluşturmak için motivasyon her chunk bir döngünün gövdesinden geliyor, ancak aynı stil her chunk üzerinde yorum yapmanıza izin veriyor.
Gilles 'SO- kötülük' dur '21

1
Örnek için teşekkürler. Örneğim temel olarak yalnızca bir komuta argüman olarak verilen uzun bir ad listesidir. Yorumlara her adın eklenmesini istiyorum, çünkü bu bağlamda kalmamın en kolay yoludur. Komutu parçalara ayırmanın açık bir yolunu görmüyorum ve eğer yaparsam daha uzun sürebilir ve zaten yeterince uzun.
Faheem Mitha

6

Bunu Bash dizilerini kullanarak yapabilirsiniz, örn.

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

"${CMD[@]}"

Bu bir dizi tanımlar $CMDve ardından onu genişletir. Genişletildikten sonra sonuçtaki çizgi değerlendirilir, bu durumda bu durumda echo fooyürütülür.

Arasındaki metin (ve )diziyi tanımlayan ve bir çizgi üzerinde her şey sonra çok, her zamanki bash sözdizimi tabidir #göz ardı edilir.

Alıntılanan boşlukların korunması hakkında not

${CMD[@]}bir boşlukla ayrılmış tüm öğelerin birleştirilmesi olan tek bir dizgiye genişler . Bir kez genişledikten sonra Bash , genellikle istediğimiz gibi olmayan dizeyi normal şekilde belirteçlere ayırır (cf $ IFS ).

Aksine, genişleme çift tırnak içine alınırsa, yani "${CMD[@]}"dizideki her öğe korunur. Arasındaki farkı düşünün hello world second itemve "hello world" "second item".

Açıklayıcı örnek:

# 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

Cevap için teşekkürler, @RobM. Öyleyse öneriniz, bash dizisindeki listedeki öğeler hakkındaki yorumları / meta bilgileri eklemek mi? Kullanmaya çalıştığım komut türüne bir örnek ekleseydim bu soru muhtemelen daha faydalı olurdu. Neden yapmadığımı bilmiyorum.
Faheem Mitha

Bah, anlaşılan soruyu dikkatlice okumadım. Bağlandığın soruyu sorduğunu sanıyordum. Hata. :)
RobM

${CMD[@]}tek bir dizeye genişlemez . - Birçok dizgiye genişler: Sadece dizinin her öğesi için değil, her öğedeki boşlukta da bölünür. (Yani: tamamen işe yaramaz)
Robert Siemer

4

Yapmayın $(: comment). Bu bir yorum değil - bu bir deniz kabuğu - çoğu kabuk için tamamen yeni bir kabuk süreci. Amacınız , girişinizle daha az değil, daha fazla değil, bunun ne işe yaradığıdır - anlamsız olsa bile.

Onun yerine yapabilirsin ...

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>

Temelde orada olan şey, kabuğun bir ikame yapmasıdır. Özel kabuk parametresinin değerini $-her seferinde iki kez değiştirir. Zaten kısa bir dize, ama olduğu zaman set - ve iç ikame yüzden - Dış gelen şeridine bir desen olarak yorumlanır - vermez kullandığım parantez arasındaki içeriğine genişletmek -genişleme formu.

İşte:

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

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

Görmek? Yani sadece iki kez genişledi. Kabuk parametrenin ayarlandığını tespit ettiği anda isteğe bağlı genişleme alanındaki her şey atılır, hemen hemen yok edilir ve kendisinden kaldırılan tüm değerine genişler ve hiçbir şeyden hiçbir şey yapmaz. Çoğu kabukta, kaçış tırnaklarına bile ihtiyacınız olmaz, ancak bashbunu gerektirir.

Daha da iyisi:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.