「zsh」で変数の解釈を変更するには?

「zsh」で変数の解釈を変更するには?

変数を設定しました。TEMPP='-I ../dir1 -I ../dir2'

だから私は走る

gcc -M $TEMPP somefile.c

含まれているファイルの検索リストに../dir1含まれていないように見え、../dir2変数の先頭にスペースがある場合(例:

TEMPP=' -I ../dir1 -I ../dir2'

エラーが報告されます。

gcc: -I ../common1 -I ../encrypt: No such file or directory

だから変数をファイルとして扱うようです。

おそらく、この問題を避けるためにディレクトリを分離することができます。ただし、含まれているディレクトリはdirs他のコマンドによって生成され、数値は一定ではありません。

それでは、コマンドの変数をリテラルとして処理し、整数文字列やファイル名ではなくコマンドラインから手動入力のように見えるようにするにはどうすればよいですか?

zshまあ...これはbashでのみ発生しますが、bashではうまく動作することがわかりました。おそらく、変数zshの拡張は特別かもしれません。

だから誰でもzshでこれをうまく機能させる方法を教えてくれたらとても感謝します。それ以外の場合は、bashでのみこれを実行できます。

答え1

"$TEMPP"私は空白が解釈されるかどうかを制御しようとしていると思います。 (これはGCCの問題ではなく、シェルがコマンドラインを解析する問題です。)

これがbashすること:

$ F="foo bar baz"
$ for f in $F; do echo $f; done
foo
bar
baz

これがzshすること:

$ F="foo bar baz"
$ for f in $F; do echo $f; done
foo bar baz

zshスペースを説明する必要があります。 zshでこれを行うエレガントな方法があるかもしれません(わかりませんが、質問のタイトルを変更してタグ付けすると、より便利な答えが得られます)。これは問題を解決しますが、問題に対する負担は少し大きくなります。

eval gcc -M $TEMPP somefile.c

答え2

zshでは、他のBourneスタイルのシェルとは異なり、変数置換の結果はワイルドカードパターンとして解釈される単語に分割されません。したがって、zshで書くと

a='hello *.txt'
echo $a

これにより、hello *.txt他のシェルとは異なり、次のようなものが表示されますhello bar.txt foo.txt

個人用の単語分割を設定できます。拡張そして$=TEMPPsetopt sh_word_splitすべての拡張子に対して単語区切りを有効または設定できますemulate sh

これらのコマンドをmakefileに入れて、真のBourneスタイルシェル(インストールされているすべてのもの/bin/sh)でそれを実行する必要があります。インタラクティブな使用と独自のスクリプトのためにzshを予約してください。

答え3

可変数の値を保持する変数を配列と呼びます。

var=value

スカラー変数の割り当て構文は次のとおりです。一つ値は a に割り当てられます。スカラー変数

var=( one two 'three or 3' )

はい配列変数値を割り当てることができる割り当て構文乱数(でも0²)値配列/リスト変数

var[n]=foo

スカラー割り当て構文でもありますが、割り当ては一つ配列のn番目の要素の値です。

欲しいものは次のとおりです。

extra_options=( -I ../dir1 -I ../dir2 -I '/opt/my software/include' )
gcc -M $extra_options somefile.c

拡張は、$extra_options配列の空の要素$extra_options(存在する場合)をスキップ$scalarします。いいえ空の場合、引数は代わりに空の要素です$scalar

"$scalar"空の要素を保存するには、or "$array[@]""${(@)array}"または"${array[@]}"bashなどのksh様シェルと互換性があり、"$@"Bourneシェルを思い出させる)が必要です。

他のBourneに似たシェルでは、次の点に注意してください。

TEMPP='-I ../dir1 -I ../dir2'
gcc -M $TEMPP somefile.c

$TEMPP暗黙的にいわゆる話すことを体験してください。分割+グローバル$TEMPP演算子を使用すると(幸いにも!)の値はシェルコードにそのまま含まれているようには見えませんgcc -M -I ../dir1 -I ../dir2 somefile.c

ケース 4の場合は次のようになります。

TEMPP='foo>/etc/passwd;reboot' # or '$(reboot>/etc/passwd)'
echo $TEMPP

/etc/passwdたとえば、上書きして再起動します。変数拡張中は、シェル構文(;>演算子、${...}拡張子$(...)、引用符を含む)は認識または処理されません。ただし、zshやその他のより一般的な最新のシェル(rc、es、fish、akanga ...)や他のプログラミング言語のようにそのまま拡張されていませんが、代わりに分割+glob演算子を使用します。

値は$TEMPP文字のみで分割され、$IFSワイルドカードとして表示されます(ファイル名の生成またはパス名拡張とも呼ばれます)。これは次のことを意味します。

TEMPP='-I ../dir1 -I ../dir2'
gcc -M $TEMPP somefile.c

これは行$IFSを解釈するときに空白文字が含まれている場合にのみ機能し、gcc...他の文字は含まれません$TEMPP(幸いにもデフォルトの場合$IFS)。たとえば、が含まれている場合、および$IFSパラメータigcc使用して呼び出されます。-I ../dr1 -I ../dr2

そして:

TEMPP='-I ../dir1 -I ../dir2 -I "/opt/my software/include"'
gcc -M $TEMPP somefile.c

シェル構文(引用符など)を解釈せずに分割のみを実行するため、機能しません。$IFSしたがって、スペースを含むパラメータを渡す必要がある場合は、分割に別の区切り文字を使用する必要があります。例:

TEMPP='-I,../dir1,-I,../dir2,-I,/opt/my software/include'
IFS=,
gcc -M $TEMPP somefile.c

例えば。値に*など?のワイルドカード演算子が含まれている場合は、拡張する前にコマンドを実行してワイルドカード文字が拡張されないようにする必要が[...]あります。set -o noglobまた、見ることができますbash / POSIXシェルで変数を引用することを忘れてしまうセキュリティリスクBourneに似たシェル(zshを除く)の誤ったデザインがセキュリティに与える影響。

zshで-splittingおよび/またはglobbingが必要な場合$IFS(ただし、通常は他のほとんどの最新のシェルのようにzshに配列がない)要求する必要があります。明らかに$=scalar分割 on は、$IFS内容$~scalar$scalarパターンとワイルドカード、またはその両方として扱うため、他の Bourne 様シェル$=~scalarと同じです。$scalar

を使用する代わりに、区切り${(s[whatever])scalar}文字で分割を参照し、行eed(改行文字とも呼ばれる)またはNULで分割する方法を簡単に参照してください。$IFS${(f)scalar}${(0)scalar}f

zsh他のBourne型またはKorn型シェル用に書かれたコードを解釈する必要がある場合は、そのコードを使用またはshエミュkshレートできます。ここで、これらのシェルとの互換性は次のように改善されます。

  • emulate ksh:シミュレーションを明示的に変更します(デフォルトのemulate zsh通常モードを復元しますが)。
  • emulate -L ksh:同じですが、Lローカルでのみ可能です(たとえば、現在の関数内など)。
  • emulate ksh -c 'ksh/bash code here'あるいは、emulate ksh -c 'source some-ksh-or-bash-script'そのシミュレーションモードで与えられたコードを解釈するだけです。

sh または ksh エミュレーションでは、IFS スプリットとワイルドカードの指定は、sh/ksh/bash のようにリストのコンテキストで引用されていない引数拡張時に暗黙的に実行されます (そして、シェルの動作に影響を与える他の多くのshwordsplitオプションglobsubstは次のように動作します.するように調整されます。


1set var = ( one two 'three or 3' )配列を導入した最初のシェルであるcshに触発され、後でset -A var one two 'three or 3'ksh93(以前のバージョンのkshにもこの機能があったにもかかわらず)、bashやyashなどの他のシェルによってコピーされました。

²注:ksh93は最初に配列を作成するため、var=()宣言はありません。var化合物配列変数の代わりに変数。

立方体1つの例外を除いて、zshおよび他のすべてのシェルで:ksh(そしてzshの代わりにkshをコピーするbash)、ここで配列インデックスは0から始まり、配列はスパースなので、インデックス0の要素も設定されると、2番目の要素がすべて割り当てarray[1]=xられます。array[123]=x追加設定なしの要素範囲は0〜122です。

実際、これは70年代初頭の最初の(非常にシンプルで原始的な)Unixシェルの場合でした。このシェルには変数もなく、コマンドの置換もありませんでしたが、$1この$9ような拡張位置引数がありました。

関連情報