継続文字の後にコメントがあるbash複数行コマンド


29

検討する

echo \ # this is a comment
foo

これは与える:

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

Webでいくつか検索した後、姉妹サイトのStack OverflowでDigitalRossのソリューションを見つけました。だからできること

echo `: this is a comment` \
foo

または代わりに

echo $(: this is a comment) \
foo

ただし、DigitalRossは、これらのソリューションが機能する理由を説明しませんでした。説明をお願いします。彼はコメントで答えた:

以前は、gotoこのように指定されたラベルに分岐するシェルコマンドがあり:ました。gotoなくなっていますが、まだ使用できる : whatever構文を... :今すぐ解析されたコメントの一種です。

しかし、移植性の議論を含め、詳細とコンテキストが欲しいです。

もちろん、他のソリューションがある場合は、それも良いでしょう。

前の質問「シェルスクリプトで複数行のコマンドをコメントする方法」も参照してください


以下の議論からメッセージを持ち帰ってください。これ`: this is a comment`は単なるコマンド置換です。の出力: this is a commentは何もなく、それはの場所に置かれ`: this is a comment`ます。

より良い選択は次のとおりです。

echo `# this is a comment` \
foo

回答:


25

コメントは、継続行を許可せずに、最初の改行で終了します(シェルトークン認識ルール10を参照)。したがって、このコードは別のコマンドラインにあります。foo

echo # this is a comment \
foo

最初の提案については、バックスラッシュの後に改行が続くのではなく、スペースを引用しているだけです。

echo ' # this is a comment'
foo

$(: this is a comment)コマンドの出力を置き換えます: this is a comment。そのコマンドの出力が空の場合、これは行の途中にコメントを挿入する非常に紛らわしい方法です。

魔法はありません::通常のコマンドであるコロンユーティリティは、何もしません。コロンユーティリティは、シェルの構文にコマンドが必要なのに、何もすることがない場合に便利です。

# 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

別のユースケースは、変数がまだ設定されていない場合に変数を設定するイディオムです。

: "${foo:=default value}"

gotoについての発言は歴史的なものです。コロンユーティリティの日付も、以前からバックBourneシェル、すべての方法トンプソンシェル持っていた、のgoto命令を。コロンはラベルを意味していました。コロンはgotoラベルのかなり一般的な構文です(sedにはまだあります)。


なるほど、分かりました。あなたが知っているこのコンテキストにコメントを挿入するより良い方法はありますか?
ファヒムミタ

3
@FaheemMitha引用したスレッドで推奨されているように、コマンドを管理可能なチャンクに分割し、各チャンクにコメントを付けます。コマンドが非常に複雑で、途中でコメントが必要な場合は、それを単純化するときです!
ジル 'SO-悪であるのをやめる'

1
さて、問題のコマンドには多くの引数があります...たくさんのビデオファイルを1つのファイルに変換しています。私はそれを単純化する直接的な方法を見ていません。ある種のリストを作成して、引数として渡すこともできますか?それは別の質問かもしれないと思います。
ファヒムミタ

@FaheemMithaの例:make_FIND、への引数の長いリストを作成するクイックスクリプトfind。ここで、チャンクごとにそれを構築する動機は、各チャンクがループの本体に由来することですが、同じスタイルで各チャンクにコメントすることができます。
ジル 'SO-悪であるのをやめる'

1
例に感謝します。私の例は、基本的にコマンドの引数として与えられた名前の長いリストです。それぞれの名前にコメントを付けたいのですが、それは私がコンテキストを維持する最も簡単な方法だからです。コマンドを断片に分割する明白な方法は見当たりません。もしそうなら、それはさらに長くなるかもしれませんし、すでに十分に長いです。
ファヒムミサ

6

これは、Bash配列を使用して実現できます。たとえば、

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

"${CMD[@]}"

これは配列を定義し、$CMDそれを展開します。展開されると、結果の行が評価されるため、この場合echo fooは実行されます。

との間のテキストは配列()定義し、通常のbash構文に従うため、その後の行のすべて#は無視されます。

引用符で囲まれた空白の保存に関する注意

${CMD[@]}スペースで区切られたすべての要素の連結である単一の文字列に展開されます。展開されると、Bashは通常の方法で文字列をトークンに解析します($ IFSを参照)。

対照的に、展開が二重引用符でラップされている場合、つまり"${CMD[@]}"、配列内の各要素は保持されます。違いを検討hello world second itemしてを"hello world" "second item"

実例:

# 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

答えてくれてありがとう、@ RobM。だから、あなたの提案は、リスト内のアイテムに関するコメント/メタ情報をbash配列自体に含めることですか?この質問は、使用しようとしている種類のコマンドの例を含めておけば、おそらくもっと役に立つでしょう。なぜそうしなかったのか分かりません。
ファヒムミタ

ああ、あなたの質問を注意深く読んでいないことがわかった。あなたがリンクした質問をしていると思いました。おっとっと。:)
RobM

${CMD[@]}単一の文字列に展開されません。–多くの文字列に展開されます。配列の各要素だけでなく、各要素の空白も分割されます。(すなわち:完全に役に立たない)
ロバートシーマー

4

しないでください$(: comment)。それはコメントではありません-それはサブシェルです-ほとんどのシェルのための別のまったく新しいシェルプロセスです。あなたの目標は、あなたの入力でより多くのことではなく、より少ないことをすることです。

代わりにできます...

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>

基本的にそこに何が起こっているのかは、シェルが置換を行っていることです。特別なシェルパラメータの値を$-毎回2回置き換えます。とにかく短い文字列ですが、常に設定されています-したがって、外側から削除するパターンとして解釈される内側の置換は、拡張フォームを使用するときに括弧の間の内容に展開されません-

ここに:

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

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

見る?したがって、2回拡張されます。シェルは、パラメータが設定されていることを検出するとすぐに、オプションの展開フィールドのすべてがほぼ破棄され、その値全体に展開され、それ自体から削除され、まったく何もなくなります。ほとんどのシェルでは、引用符をエスケープする必要はありませんが、引用符はbash必要です。

さらに良いのは:

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.