web-dev-qa-db-ja.com

GNU一部のシェルの{}を見つけてマスキングします-どれですか?

GNUのmanページは、状態を見つける:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the Shell. 

それは男からfind(GNU findutils)までです。

これをbashとdashでテストしましたが、どちらも{}をマスクする必要はありません。ここに簡単なテストがあります:

find /etc -name "hosts" -exec md5sum {} \; 

本当にブレースをマスクする必要があるシェルはありますか?見つかったファイルに空白が含まれているかどうかには依存しないことに注意してください(bashから呼び出されます)。

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

見つかったファイルがサブシェルに渡されると、これは変更されます。

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

これは次の方法で解決できます。

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

対照的に:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

しかし、それはmanページが話していることではありません、そうですか?では、どのシェルが{}を別の方法で扱いますか?

35
user unknown

概要{}を展開したシェルがあった場合、それは今では本当に古いレガシーのものです。

BourneシェルおよびPOSIX準拠シェルでは、中かっこ({および})は通常の文字です((および)のようなWord区切り文字である;および&とは異なり、[および]はグロビング文字です)。次の文字列はすべて文字どおりに出力されることになっています。

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

単一のブレースで構成されるワードは 予約語 であり、コマンドの最初のワードである場合にのみ特別です。

Kshは、Bourne Shellの非互換の拡張機能としてブレース拡張を実装しています。これはset +Bでオフにできます。この点で、bashはkshをエミュレートします。 Zshはブレース展開も実装しています。そこでは、set +Isetopt ignore_bracesemulate shでオフにすることができます。 findxargs への引数の一般的な使用により、Wordの部分文字列({}など)であっても、これらのシェルはいずれもfoo{}barを展開しません。

単一のUnix v2

一部の歴史的なシステムでは、中括弧は制御演算子として扱われます。将来の標準化活動を支援するために、移植可能なアプリケーションでは、引用符で囲まれていない中括弧を使用して文字自体を表すことを避けます。 ISO/IEC 9945-2:1993規格の将来のバージョンでは、{}を個別に制御演算子として扱うことが必要になる可能性がありますが、トークン{}は、 find{}構文を使用しました。

このメモは、標準の後続のバージョンでは削除されました。 findの例 は、 xargsの例 と同様に、引用符なしで{}を使用しています。 {}を引用しなければならない歴史的なBourneシェルがあったかもしれませんが、それらは今では本当に古いレガシーシステムでしょう。

私が手元にあるcsh実装(OpenBSD 4.7、 DebianのBSD csh 、tcsh)はすべて{foo}fooに拡張しますが、{}はそのままにします。

3.0.0より前のバージョンのfishシェルでは、{}を引用する必要がありました。

$ fish -c 'echo find -exec {} \;'
find -exec  ;

そしてrcシェルでは(akangaにもとづくrcではなくesではありません):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

これらは、fishが最初に2005年にリリースされて以来(そのテキストまたは類似のものがすでに1994年にそこにあった一方で)、そのテキストを書いたときにGNUのドキュメントの作成者が考えていたシェルではない可能性があります)およびrcは、もともとUnixシェルではありませんでした。

csh(ブレース展開を導入したシェル)の一部のバージョンには、それを必要とする噂がいくつかあります。しかし、2BSDでのcshの最初のリリースはそうしなかったので、それらを信用するのは難しい。ここでは、PDP11エミュレータでテストされています。

# echo find -exec {} \;
find -exec {} ;

そして 2BSDのmanページcshは明確に述べています

特殊なケースとして、 `{'、`}'および `{} 'はそのまま渡されます。

したがって、cshまたはtcshの後続のバージョンが後でそれを壊した場合、それは非常に奇妙だと思います。

いくつかのバージョンではいくつかのバグを回避するためでした。それでも2BSD csh(2.79BSD、2.8BSD、2.11BSDでも同じ):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

しかし、引用は役に立ちません:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

コマンド置換全体を引用できます。

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

しかし、それはその外部エコーに1つの引数を渡しています。

cshまたはtcshでは、次のように単独ではない場合、{}を引用符で囲む必要があります。

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(そのようなfindの使用は、一部のfindsが{}を拡張するだけなので、移植性がありません)。

12

つまり、cshbashおよび他の最新のシェルは、ユーザーがnullブレース展開を要求していないことを認識しています。 (モダンcshは実際にはtcshであり、{}今までに正気に。)

1
geekosaur