4

次のようなファイル/ディレクトリのリストが渡されるexcept.shという名前のbashスクリプトがあります。

$ ls
a b c d/
$ ./except.sh b c

この方法以外で呼び出す場合a d/は、指定された名前を除くすべてのファイル/ディレクトリに展開する必要があります。

これを実装しようとした方法は次のとおりです。

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

# set IFS to | so that $* expands correctly
IFS='|'

printf '%s' !("$*")

パラメータb cとして指定すると、最後の行は次のように展開されます。

printf '%s' !(b|c)

a d印刷されます。しかし、驚いたことに、

abcd

印刷されます。私は何が間違っているのですか?

4

2 に答える 2

3

問題は、二重引用符で囲まれていることです。これは、アスタリスクを展開しないの$*と同じように、その内容がパターンとして扱われないことを意味します。echo "*"外側のパターンと内側の引用部分を組み合わせると、後者は自動的にエスケープされるため、のよう!("b|c")に扱われ!(b\|c)ます。存在しないファイルの否定はb|c、ディレクトリ内のすべてのファイルに自然に拡張されます。

IFS追加の問題は、に設定すると拡張グロブが台無し|になることです。そのため、パターンを拡張する前にリセットする必要があります。したがって、2つのステップで展開を実行する必要があります。最初にパターンを計算し、次にリセットIFSして展開します。

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

# temporarily set IFS to | so that $* expands to part an extended pattern
old_ifs=$IFS
IFS='|'
pattern="!($*)"
IFS=$old_ifs

printf '%s' $pattern
于 2013-01-15T14:48:32.933 に答える
2

問題はIFS変数のオーバーライドが原因です(この変数をオーバーライドした後、bashパターンマッチングは奇妙な動作をします。たとえば、ls -d !(b|c)設定の前後に試してくださいIFS)、以下が機能するはずです。

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

PARAMS=$(tr ' ' '|' <<< $*)
printf '%s' !($PARAMS)
于 2013-01-07T15:02:56.757 に答える