Bash:サブシェルからエスケープされた引用符

Bash:サブシェルからエスケープされた引用符

次のコマンドを実行するとき:

#!/bin/bash
while IFS= read -r -d '' file; do
    files+=$file
done < <(find -type f -name '*.c' -print0)
echo "${files[@]}"

私は次のような結果が得られません。

#!/bin/bash
find_args="-type f '*.c' -print0"
while IFS= read -r -d '' file; do
    files+=$file
done < <(find $find_args)
echo "${files[@]}"

2番目のシーンを1番目のシーンと同じように変更するにはどうすればよいですか?

私の理解は、二重引用符の中に一重引用符があるため、一重引用符がエスケープされ、次のような誤った拡張が生成されることです。

find -type f -name ''\''*.c'\'' -print0

ベストアンサー1

ブレア首相の回答正確ですが、ここで実際に何が起こっているのかを分析するには(欠落しているmasterデータベースのスペルエラーを無視して-name):

#!/bin/bash
while IFS= read -r -d '' file; do
    files+=$file
done < <(find -type f -name '*.c' -print0)
echo "${files[@]}"

プロセス置換()で始まるシェルでは、<(...)bashは次のコマンドを解析します。

find -type f -name '*.c' -print0

globが*.c参照されるので、bashはいいえ拡張してください。ただし、一重引用符は削除されます。したがって、findプロセスの開始時に表示されるパラメータのリストは次のとおりです。

-type
f
-name
*.c
-print0

これらのパラメータは区切り文字で区切られます。ヌルバイト、空白か改行なし。これはシェルレベルではなくCレベルにあります。これは、C言語を使用してexecve()プログラムを実行する方法に関連しています。

それでは、次のコードを比較してみましょう。

#!/bin/bash
find_args="-type f -name '*.c' -print0"
while IFS= read -r -d '' file; do
    files+=$file
done < <(find $find_args)
echo "${files[@]}"

変数の値はfind_args次のように設定されます。

-type f -name '*.c' -print0

(二重引用符は値の一部ではありませんが、一重引用符文字ははい。)

コマンドがfind $find_args実行されると、man bashトークンは次のように$find_argsパラメータ拡張が適用されます。続いて噴射続いてパス名拡張(別名グローバル拡張)。

パラメータ拡張後は-type f -name '*.c' -print0後ろに参照が削除されました。したがって、一重引用符は削除されません。

単語を分割すると、次のような個々の単語が得られます。

-type
f
-name
'*.c'
-print0

それからパス名拡張。もちろん、'*.c'通常はファイル名に一重引用符を入れないので、どんなものとも一致する可能性がないので、結果は次のようになります。可能'*.c'リテラルモードで渡されるため、findプライマリ-nameデータベースはすべてのファイルで失敗します。 (名前が一重引用符で始まり、3文字で終わるファイルがある場合にのみ成功します.c'。)


編集:実際にそのようなファイルが存在する場合、globは'*.c'そのファイルや他のそのようなファイルと一致するように拡張されます。拡張[実際のファイル名]find柄。 したがって、-print0マスタノードに到達するかどうかは、(a)一つそのようなファイル名と(b)対応するファイル名(globとして解釈される)が一致するかどうか。

例:

touch "'something.c'"その時走ると全体的な状況 '*.c'展開すると、'something.c'デフォルトのfindファイル-name 'something.c'も一致して印刷されます。

実行すると、touch "'namewithcharset[a].c'"globは'*.c'シェルによってglobに拡張されますが、findデフォルトは-name 'namewithcharset[a].c'いいえ一致自体 - 一致のみが'namewithcharseta.c'存在しないため、-print0到達できません。

を実行すると、touch "'x.c'" "'y.c'"globは'*.c'次に展開されます。両方findfilename は有効なデフォルトのファイル名ではないため、出力エラーを引き起こす可能性があります'y.c'(そしてハイフンで始まらないので、それはできません)。


nullglobこのオプションを設定すると、他の動作が発生します。

また見なさい:

おすすめ記事