GNUはいくつかのシェルの{}を見つけてマスクします-どれですか?


34

GNU findの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)4.4.2までです。

今、私はこれを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

しかし、それはマニュアルページが言っていることではありませんか?それでは、どのシェルが{}異なる方法で処理しますか?


@Volker Siegel:編集は意図的に行われた可能性がありますが、現在の検索マニュアルを確認し、修正が間違っています。また、悪い習慣である編集を要約する機会を逃したため、変更をロールバックします。ごめん、仲間。
ユーザー不明

ああ、それが何かを壊した場合、それをロールバックしてくれてありがとう。私は、レンダリング定義のアーティファクトとしてこれらの「タイポグラフィ引用符」を生成するために使用されるマニュアルページ形式を生成するテキストコンパイラを覚えていました。また、完璧な印刷フォーマットのためにTeXにレンダリングできます。構文の強調表示を混同したため、引用に気付きました。私は、コードで使用されるとき、異常な最初の引用が間違っていると仮定し、それでもそれを仮定します。2つの変更は、コードではなく説明テキストにありました。したがって、それらをタイポグラフィ(美的レンダリング)として見ると、それらは正しいです。
フォルカーシーゲル

情報出力レンダリングのように見えますが、同じ引用符が両側で使用されます。私の変更が元のものと異なっていたことは間違いありません、あなたは正しいです。しかし、それは問題を引き起こしましたか?(最初の引用は、人のレンダリング定義のバグと考えています。私の知る限り、それはタイポグラフィの唯一のケースです。)
Volker Siegel

チェックしたところ:コマンドラインで「{}」が機能しません。技術的には正しいのですが、疑いを持たないユーザーがコピーして貼り付けようとすると奇妙なエラーが表示されるのは好きではありません。
フォルカーシーゲル

@VolkerSiegel:それはコードではなく散文ですので、ここでユーザーがコピーアンドペーストするものは何ですか?そして、それは2011年からのmanページの引用です。私がmanページを修正した理由を指摘するためにパッセージを修正する値は見当たりません。トピックは非常に複雑です。これがあなたの質問であれば、私はあなたを説得しようとはしません。マニュアルページを正確に引用しますが、私の質問のために、私は妥協する気分ではありません。引用は引用です。
ユーザー不明

回答:


26

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

BourneシェルおよびPOSIX準拠のシェルでは、中かっこ({および})は通常の文字です((and )とは異なり、;and &、および[and ]はグロブ文字です)。次の文字列はすべて、文字通り印刷されることになっています。

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

単一の中括弧で構成される単語は予約語であり、コマンドの最初の単語である場合にのみ特別です。

Kshは、Bourneシェルに対する互換性のない拡張としてブレース拡張を実装します。これはでオフにできますset +B。Bashはこの点でkshをエミュレートします。Zshはブレース拡張も実装しています。そこで、set +Iまたはsetopt ignore_bracesまたはでオフにできますemulate sh。これらのシェル{}はいずれも、単語の部分文字列(例:)であっても、andのfoo{}bar引数で一般的に使用されるため、展開しません。findxargs

単一のUnix v2では

一部の歴史的なシステムでは、中括弧は制御演算子として扱われます。将来の標準化活動を支援するために、ポータブルアプリケーションは、引用符で囲まれていない中括弧を使用してキャラクター自体を表すことを避ける必要があります。1993標準ことが必要な場合があります:ISO / IEC 9945-2の将来のバージョンがいる可能性がある{}トークンがあるが、制御事業者として個々に処理すること{}おそらく頻繁に使用されるのこのから特殊なケースの免除になりますfind {}構築物。

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

私が手にしているcsh実装(OpenBSD 4.7、DebianのBSD csh、tcsh)はすべて拡張さ{foo}れてfooいますが、放置されてい{}ます。


1
@geekosaur:マークダウンのごく一部のみがコメントで機能します。あなたが何を言おうとしているのか分かりません。これがkshなどのブレース拡張に関するものである場合は、「Kshはブレース拡張を互換性のない拡張として実装します」で始まる私の段落を読んでください。
ジル 'SO-悪である停止

2
それでしたbash(参照$BASH_VERSION)。ブレースの拡張は非常に活発です。
ギーコサウルス

2
それポイントでした。{}構文が発祥cshますが、{}空の文字列に展開しました。新しいシェルはそれが無意味であることを認識しますが、まだ古いものがいくつかcshあります。
ギコサウルス

1
@geekosaur:どの特定のプラットフォームでどの特定のcshバージョンを言うことができますか?私はそれを自分でテストしたい(Linuxで可能な場合)か、人が自分でテストすることを確信します。
ユーザー不明

1
@geekosaurは、{}fooに展開されますfooが、{}に展開され{}(バックティック内にある場合を除き、引用符は役に立たない)、そのように文書化されました。2BSD(最初のリリース)、2.79BSD、2.8BSD、および2.11BSDのcshで検証しました。
ステファンシャゼル

12

{}バージョンで引用する必要がfish3.0.0より前のシェル。

$ 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 findドキュメントの著者が念頭に置いていたrcシェルではなく、もともとUnixシェルではありませんでした。

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

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

また、2BSDcshmanページには次のように明記されています

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

したがって、後で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使用法は移植性がありません。一部findのsは{}単独で拡張されるためです)。


1

一言で、cshbashまた、他の最新のシェルは、ユーザーがおそらく中括弧の拡張を要求していないことを認識しています。(Modern cshは実際にtcshあり{}、今では正常に処理されるかもしれません。)


聞いてうれしいですが、私は反対のことを求めています。シェルはそれを正常に処理しません。
ユーザー不明

Linuxシステムのすべてが新しいであるという理由だけで、誰かが入って情報ページの追加引用への参照をリッピングすると想定していcshます。誰もがLinuxでGNUユーティリティを実行しているわけではありません。実際、バンドルされたコマンドが制限されている古い商用Unixシステムにインストールすることは非常に一般的です。(cshシステムスクリプトはオリジナルの特異性に依存する可能性があり、cshユーザーがすべて新しいバージョンを使用するように設定されている場合でもcshrootほとんどの場合、バンドルバージョンを維持する必要があるため、これらのシステムでの置換はあまりありません。)
geekosaur

2
いいえ。私は、ウィキでは常に「{}」を使用するようアドバイスする必要があると言っている人と議論しています。そして今、私は私が知らないksh、zsh、tcsh、cshまたはXYZshのような私が使用していないシェルがあるかどうか、この主張が真実であるかどうか、または私が正直に仮定できるかどうかを知りたいありません。「{}」を必要とするさまざまなUnix向けのシェルがある場合、それは文章がまだmanページにある理由の良い説明ですが、Linux初心者向けのアドバイスとしては適切ではありません。
ユーザー不明

今、私はpdksh正しいことをするかどうか疑問に思っています... それに対する正しい答えはおそらく「ksh最近はFOSSです」です。
ギコサウルス

4
mksh、ksh93、bash、zshなどのPdkshは、間にカンマがある場合(または..ksh93、bash、zshの場合)のみブレースを展開します。(t)cshのみがに展開さ{foo}foo、それでも{}放置されます(少なくとも最近のBSDでは)。
ジル「SO-停止されて悪」
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.