これはフォローアップです。質問SOに投稿されました。
except
このようにして、指定されたファイル名/ディレクトリを除くすべてのファイル名/ディレクトリを印刷する必要があるスクリプトを作成しました。
$ ls
a b c d
$ rm $(except b d)
$ ls
b d
これまでに作成したスクリプトは次のとおりです。
shopt -s extglob
shopt -s nullglob
old_ifs=$IFS
IFS='|'
matches="!($*)"
IFS=' '
printf '%s' $matches
IFS=$old_ifs
これはある程度機能しますが、主な問題はprintfが(空白)IFS
設定を尊重しないようです。
の間にスペースなしで印刷されます。代わりにechoを使用すると機能します(追加の改行を除く)。しかし、互換性のためにこれを行うにはprintfを使用したいと思います。この目標をどのように達成できますか?私は何が間違っていましたか?
また、修飾子を試してみました%q
が、目的の結果は出ませんでした。
printf '%q' $matches
答え1
$ ls a b c d $ rm $(except b d) $ ls b d
"except"
コマンドに渡す前にシェルが出力を分割(および追加の拡張)する方法を決定する方法がないため、これは機能しないか、少なくとも信頼できませんrm
。
あなたの質問に答えるためにprintfは使用されません$IFS
。 IFSを使用する唯一のコマンドはですread
。さらに、シェルは接続のトークン化と位置引数に$ IFSを使用します"$*"
。
次のことができます。
printf '%s ' $matches
または
printf '%s\n' $matches
しかし、再び、
rm $(except a b)
except
そのコマンドラインを解釈するシェルは独自の状況に応じて出力を分割し$IFS
(デフォルトは空白、タブ、または改行であるため、空白以上を使用しても\n
違いはありません)、ワイルドカードも拡張します。
a
したがって、and以外のファイルがandの場合は出力b
され"this file.txt"
、andを削除しようとします(該当する名前のすべてのファイルに拡張されるため)。**a**
except
"this file.txt **a** "
this
file.txt
a
**a**
a
末尾の空白なしで空白と一致を連結するには、次のようにします。
IFS=
set -- $matches
IFS=' '
matches="$*"