ダッシュでエスケープスペース

ダッシュでエスケープスペース

私はこのようなことをしたい。

$ touch a\ b
$ cmd=cat\ a\ b
$ echo $cmd
cat a b
$cmd
cat: a: No such file or directory
cat: b: No such file or directory

ファイルにスペースに問題がありますa b。だからこれを試しました。

$ cmd=cat\ a\\\ b
$ echo $cmd
cat a\ b
$ $cmd
cat: a\': No such file or directory
cat: b: No such file or directory

これも失敗しました。$cmd猫が走らないようにするにはどうすればよいですかa b

答え1

set -- cat "a b"

"$@"

これはcat単一の引数で実行されますa b。拡張"$@"(二重引用符を含む!)は、個別に引用された位置パラメータのリストになります。位置パラメータはで設定されますset

ただし、コマンド名がリスト自体に含まれることはまれです。もっと一般的になる

set -- "a b"

cat "$@"

または、実際のコマンド名変数を保持するには

cmd=cat
set -- "a b"

"$cmd" "$@"

ファイル名オペランドを設定してコマンドを実行する間にコマンドにさらにファイル名またはオプションを追加するには、次のように変更します$@

cmd=cat
set -- "a b"

# later (adding more files to the end):
set -- "$@" "more files" "some glob here-"[0-9]

# later (adding an option at the front):
set -- -v "$@"

"$cmd" "$@"

$@コマンド名がすでに存在する場合は、前にコマンド名を追加することは困難です。このような場合は、shift一時的にコマンド名を$@別の変数に入れて追加したいものを追加してから、コマンド名を再度追加する必要があります。

cmd=$1
shift
set -- "$cmd" -v "$@"

通常、位置パラメータを設定するset --よりも使用したいです。コマンドライン引数リストで、この時点以降のコマンドラインオプションを取得するコマンドラインオプションパーサーを停止しますset--がなければ、まったく異なる場合のように、文字列の前にwithを追加する--ことは不可能です。-v$@setset -v

関連:

答え2

引用符を有効または無効にするecho $cmd$cmd、コンテンツは分割+グローブを呼び出します$cmd。これはecho cat a b、シェルの構文解析を使用してに渡された別の引数に分割したcatときaに発生する状況とは関係ありません。becho

Split + globの分割はSPCの基本的な埋め込みに基づいているため、$IFS分割単語にSPCは含まれません。別の区切り文字を使用する必要があります。

IFS=:  # split on :
set -o noglob # disable glob part

cmd='cat:a b'
printf '<%s>\n' $cmd # split+glob
$cmd # split+glob

cmdevalあるいは、分割+globに依存するのではなく、シェルコマンドライン(シェル言語のコード)を含めて呼び出してそのコードを解釈することもできます。

cmd='cat "a b"'
eval "$cmd" # note the quotes to disable split+glob

関連情報