3

bashスクリプトを書いているときに、引用と評価のルールに常に混乱しています。''と""と``の違いなど、いくつかの基本的なことは知っていますが、それでも間違っていることが多すぎるようで、同じことを言うためにさまざまな方法を試してみることになります。

私が通常は力ずくで解決できる個々の問題はありますが、それがどのように機能するかについての私の概念モデルは、何らかの未知の方法で絶望的に破られているに違いないと思います。

私はlispのquote、eval、read、print、syntax-quoteシステムに問題はありません。実際、私は人々が何が起こっているのかを理解するのを助けるために小さな型を書きました:http: //www.learningclojure.com/2010/11/syntax-quote-kata-for-confused.html

私はbashに似たものを探していると思います(これははるかに複雑に思えます)。優れたモデル、またはそのようなモデルを形成するのに役立つ一連の演習により、変数が変換および評価され、印刷されて読み取られる複雑なシェルスクリプトを確認し、何が起こるかを理解できるようになります。それを試す必要はありません。

それができない場合は、プロセスをデバッグし、評価の各段階で何が起こっているかを監視するための優れた方法が非常に役立ちます。

4

3 に答える 3

9

BruceBarnettのUNIXShellQuote Tutorialは素晴らしいものであり、BashFAQ /落とし穴/単語分割の記事にはたくさんの役立つヒントがあります。簡単な要約:

引用符で囲まれていない文字列にはほとんどの文字を含めることができますが、すべて(改行など)ではなく、それらの多く(スペースを含む)をエスケープする必要があります。それらを使用しないでください-誘惑に陥った場合、スクリプトを変更した誰かが、必要になったときに引用符を含めるのを忘れていることに気付くかもしれません。

一重引用符で囲まれた文字列には、NULや改行を含むほとんどの文字を含めることができますが、一重引用符は含めることができないため、単純な値の場合にのみ役立ちます。

バックティックはコマンド用です。シェルがをサポートしていない場合にのみ使用してください$()。例:

current_dir=`pwd` # BAD! Don't do this!

割り当ての右側が引用符で囲まれていない場合、シェルはそのコマンドで単語分割を実行するため、このコマンドは不適切です。空白は視覚的に確認するのが難しいため、再現が難しいバグにつながることがよくあります。コマンドを引用するには、二重引用符を使用する必要があります。

current_dir="$(pwd)" # OK, but loses newlines at EOF

EOFの改行は特に注意が必要です。たとえば、1つの文字を追加し、それを削除することができます

# Works for some commands, but not pwd
current_dirx="$(pwd; echo x)"
current_dir="${current_dirx%x}"
printf %s "$current_dir"

、ただし、一部のコマンド(など)は出力の最後に改行を追加するため、追加の問題がありますpwd。そのため、それも削除する必要がある場合があります。

# Works for some commands, including pwd
current_dirx="$(pwd; echo x)"
current_dir="${current_dirx%$'\nx'}"
printf %s "$current_dir"

二重引用符には任意の文字を含めることができますが(Try echo -ne "\0" | wc -c)、変数にNUL文字を含めることはできないことに注意してください。

ANSI-C引用符には、 NUL(Tryの任意の文字を含めることができecho -ne $'\0' | wc -c、特殊文字の操作を容易にする便利なエスケープコードを提供します。

printf %s $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
printf %q $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
touch -- $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
rm -- $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
于 2012-04-03T13:50:38.277 に答える
1

生のテキストを引用するために一重引用符を使用''します(バックスラッシュでさえ一重引用符で何もエスケープしません):

> echo '\'
\
> echo '$PATH'
$PATH

変数( )、サブシェル呼び出し()、評価( )""など、シェルが評価するものを含むテキストを引用する場合は、二重引用符を使用します。$bla$(ls)$((5 + 3))

> echo "$PATH"
/home/alfe/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
> echo "$(ls | tail -1)"
bla
> echo "$((5 + 3))"
8

``何らかの理由で使用できない場合は、バッククォートを使用します(たとえば、の代わりに$()必要なまれなケースで。通常は、サブシェルの出力を現在のコマンドに収集するために使用します。shbash$()

> echo "$(ls | tail -1) is the last file in the current dir."
bla is the last file in the current dir.

他の人のbashコードで遭遇する主な問題の1つは、多くの場合単なる単語ですが、まれに複数の単語であるか、特殊文字を含む可能性のあるものの周りに二重引用符がないことです。したがって、可能な限り二重引用符を使用してください。

> a="four    spaces"
> echo $a
four spaces
> echo "$a"
four    spaces
于 2012-04-03T14:07:22.950 に答える
0

シェルプロンプトで、

set -x
set -v

次のPythonプログラム'args.py'を作成します

#!/usr/bin/env python

import sys
print sys.argv
for arg in sys.argv[1:]:
    for c in arg:
        print c,"|",
    print

次に、次のようなコマンド呼び出しを試してください。

U=hello\ world ; V="-->$U<--"; W="1 $U 2 $V 3"; args.py $W

何が起こっているのかについて論理的な考え方ないことに気付くまで。それは本当に気まぐれなマジックシェルピクシーによってすべて行われます。

于 2012-04-12T10:48:38.907 に答える