パススラッシュの後のbashブレースの展開


12

ブレース拡張を使用して、ファイルを別の名前で同じディレクトリにコピーしようとしています。私はbash 4.4.18を使用しています。

私がやったことは次のとおりです。

cp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}

しかし、私はこのエラーを受け取ります:

cp: cannot stat '/home/xyz/some/dir/{my-file-to-rename.bin,': No such file or directory

このような単純なブレース展開でも、同じエラーが発生します。

cp {my-file-to-rename.bin, new-name-of-file.bin}

私は何を間違えていますか?

回答:


29

ブレース展開の構文は、コンマを受け付けますが、それは、カンマの後にスペースを受け付けません。多くのプログラミング言語では、コンマの後のスペースは一般的ですが、ここではそうではありません。Bashでは、引用符で囲まれていないスペースがあるため、ブレースの展開が実行されません。

スペースを削除すると、機能します:

cp ~/some/dir/{my-file-to-rename.bin,new-name-of-file.bin}

まったく必要ではありませんが.bin、中括弧の外側に末尾を移動できることに注意してください。

cp ~/some/dir/{my-file-to-rename,new-name-of-file}.bin

ブレース展開の効果をテストするecho場合はprintf '%s '、またはprintfを使用するか、任意の形式の文字列を使用してそれを実行できます。(個人的にechoは、Bash echoビルトインはデフォルトではエスケープシーケンスを展開しないため、Bashにいるときにこれに使用します。したがって、実際に実行されるコマンドを確認するのに適度に適しています。)例:

ek@Io:~$ echo cp ~/some/dir/{my-file-to-rename,new-name-of-file}.bin
cp /home/ek/some/dir/my-file-to-rename.bin /home/ek/some/dir/new-name-of-file.bin

23

string{foo, bar}ブレースの拡張ではありません。それは2つの単語string{foo,bar}です。ブレース展開を使用するには、ブレースが同じ単語内にある必要があります。余分なスペースが不要な場合は削除するか、必要な場合は引用符で囲む必要があります。

$ printf "%s\n" aa{bb, cc}
aa{bb,
cc}
$ printf "%s\n" aa{bb,cc}
aabb
aacc
$ printf "%s\n" aa{bb," cc"}
aabb
aa cc

明確な例のために+1、ありがとうございます。評判がよければ、賛成票を差し上げます。:)
nanangarsyad

「シェルワード」について言及する必要がある他の何かがあります。。.likeシェルは単語を分割する場所をどのように知っているのか;)
Sergiy Kolodyazhnyy

-1

Bashはそのスペースを他のスペースと同様に扱います。IFSとして、内部フィールドセパレーター。これは、展開後の単語分割、およびread組み込みコマンドで行を単語に分割するために使用されます。

シェルは、IFSの各文字を区切り文字として扱い、他の展開の結果をこれらの文字の単語に分割します。IFSが設定されていない場合、またはその値がデフォルトである場合、前の展開の結果の先頭と末尾にある、、およびシーケンスは無視され、先頭または末尾にないIFS文字のシーケンスは区切りに使用されます言葉。IFSにデフォルト以外の値がある場合、空白文字がIFS(IFS空白文字)の値に含まれている限り、空白文字とスペースのシーケンスは単語の先頭と末尾で無視されます。IFS空白以外のIFSの文字は、隣接するIFS空白文字とともにフィールドを区切ります。IFS空白文字のシーケンスも区切り文字として扱われます。IFSの値がヌルの場合、
-bash(1)

エスケープせずに区切り文字を挿入すると、コマンドと引数は次のようにbashに指示されます。

  1. 「cp」
  2. 「〜/ some / dir / {my-file-to-rename.bin、」
  3. 「new-name-of-file.bin}」

引用符またはエスケープ「\」があった場合、次のようになります。

  1. 「cp」
  2. 「〜/ some / dir / {my-file-to-rename.bin、\ new-name-of-file.bin}」

「new-name-of-file.bin」が新しいファイル名でない限り、これはあなたが望むものではありません。スペースが含まれています。ブレースの展開が最初に発生し、次にチルダの展開が発生すると、bashが実行されます。

  1. 「cp」
  2. 「/path/to/home/some/dir/my-file-to-rename.bin」
  3. 「/ path / to / home / some / dir / \ new-name-of-file.bin」

単にスペースを削除するだけで、すべてが修正されます。


5
これは主に良いですが、単語の分割がオンに起こると言っているようだcp ~/some/dir/{my-file-to-rename.bin, new-name-of-file.bin}IFS、結果に影響を与えます。どちらもそうではありません。ここで、スペースはトークン化のメタキャラクターです(ステップ2)。分割が発生するときは3.5.7を参照してください。試してみてくださいIFS=xそれからprintf '[%s]\n' {a,b} printf '[%s]\n' {a, b} printf '[%s]\n' {a,xb} printf '[%s]\n' {a, xb}
エリアケイガン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.