リスト/配列があるとしましょう。
list=(a b c)
各要素をxargsにエコーする方法は?それは次のとおりです。
for v in list; do echo v; done; | xargs
もっと簡単な方法がありますか?
答え1
printf '%s\n' "${list[@]}" | xargs
これにより、list
各要素が1行に印刷され、改行で区切られたリストがに渡されますxargs
。
"${list[@]}"
に拡張される個々の二重引用符要素list
。 printf
書式文字列のプレースホルダよりも多くの引数が指定された場合、その書式文字列は再利用されます。
ただし、要素には空白、一重引用符、二重引用符、またはバックスラッシュ文字が含まれておらず、空の文字列ではない場合にのみ機能します(一部のxargs
実装はテキストのみで構成され、テキストではなく_
比較的短い)。
任意の(長すぎない1)要素(NUL文字を含まないが、現在のバージョンのbashはとにかく変数にNULを格納できない)の場合、ほとんどの実装xargs
でサポートされているNULで区切られたレコードオプションとしてリストを渡すことができます-0
(Appearing POSIX規格の次のバージョンから):
{
[ "${#list[@]}" -eq 0 ] || printf '%s\0' "${list[@]}"
} | xargs
print0
ヘルパー機能を使用すると役に立ちます。
print0() {
[ "$#" -eq 0 ] || printf '%s\0' "$@"
}
print0 "${list[@]}" | xargs -0
NetBSDを除く空のリストの場合、コマンドはecho
(デフォルトでは)引数なしで一度だけ呼び出されます。このオプションを使用すると、この-r
状況を回避できます(POSIX規格の次のバージョンでも同様)。
¹ システムコールの制限をxargs
解決するように設計されていますが、execve()
途中で個々の引数を削除しないため、単一の引数が制限より大きい場合、execve()
コマンドは実行されません。さらに、Linuxには、ほとんどのシステムに共通のすべてのパラメータと環境変数の累積サイズに対する完全な制限とは異なり、個々のパラメータのサイズに対する制限があります。
答え2
特に長いリストでなければxargs
完全にあきらめてもいいです。
list=(a b c)
# With xargs
printf "%s\n" "${list[@]}" | xargs foo # Results in « foo a b c »
# Without xargs
foo "${list[@]}" # Also results in « foo a b c »
もちろん、これをあなたのケースに適用できるかどうかは、xargs
実際のコマンドに渡したい追加のフラグが何であるかによって異なります。
これをテストするには、foo
このスクリプトを実行して上記のすべてのインスタンスをfoo
次のように置き換えます./foo
。
cat <<'EOF' > foo
#!/bin/bash
echo "Got $# arg(s): $*"
for ARG in "$@"; do echo "> $ARG <"; done
EOF
chmod a+x foo
また、デフォルトでは(ここに示すように)その引数xargs
はスペースに分割されているため、次のようになります。
list=('a b' c d) # Three arguments; the first contains a space
printf "%s\n" "${list[@]}" | xargs foo # Gives foo four arguments « a b c d »
foo "${list[@]}" # Gives foo three arguments, with the first containing a space, « 'a b' c d »