入力をループしてコマンドを実行する関数を作成しようとしていました-それらがどのように区切られているかに関係なく。
function loop {
# Args
# 1: Command
# 2: Inputs
for input in "$2" ; do
$1 $input
done
}
declare -a arr=("1" "2" "3")
$ loop echo "$arr[@]"
1
$ loop echo 1 2 3
1
$ loop echo $arr
1
ただし、 this の回答に従って、for .. in ..
は配列に対して機能します。
for item in "${arr[@]}" ; do
echo "$item"
done
スペースで区切られた値に対しても機能します。
for item in 1 2 3 ; do
echo "$item"
done
簡単に言えば、引数を渡しながら"${arr[@]}"
と1 2 3
の効果を得るにはどうすればよいですか。
また、このループの概念を、ファイルのように\n
で区切られたコンテンツなど、あらゆる種類の区切られたアイテムに拡張することもできますか? Pythonにはiterators
の概念があります。bashにも同様のものはありますか?
アレイを正しく呼び出していません。 $arr
は配列の最初の要素にのみ展開され、$arr[@]
はリテラル文字列[@]
が追加された最初の要素に展開されます。
配列のすべての要素を呼び出すには、次を使用します:"${arr[@]}"
もう1つの問題は、$2
に含まれているのは2番目の位置パラメータだけで、3番目、4番目、5番目などを反復しようとしていることです。これらはすべて$@
に格納されます。
あなたの目標を達成するためにあなたは次のようなことをすることができます:
function loop {
local command=$1
shift
for i in "$@"; do
"$command" "$i"
done
}
これにより、command
が最初の定位置パラメーターに設定され、次にシフトされて、$@
を使用して残りのパラメーターをループできるようになります。次に、配列を適切に呼び出すだけです:
$ declare -a arr=("element1" "element2" "element3")
$ loop echo "${arr[@]}"
element1
element2
element3
$ loop printf 'hello ' 'world\n'
hello world
$ loop touch file1 file2 file3
$ ls
file1 file2 file3
この関数でさまざまな区切り文字を受け入れることができるようにしたい場合は、次のようにします。
function loop {
local command=$1
local delim=$2
shift 2
set -- $(tr "$delim" ' ' <<<"$@")
for i in "$@"; do
"$command" "$i"
done
}
つまり、次のように、2番目のパラメーターを介して、使用する区切り文字を指定する必要があります。
$ loop echo '|' 'one|two|three'
one
two
three
$ loop echo '\n' "$(printf '%s\n' 'one' 'two' 'three')"
one
two
three
ただし、これにはいくつかのバグがあります(カスタム区切り文字を指定した場合でも、空白で区切られます)
あなたのループはGNU Parallelに非常に似ています:
declare -a arr=("1 a" "2 b" "3 c")
var1="1 a,2 b,3 c"
var2="1-a 2-b 3-c"
parallel -j1 echo ::: "${arr[@]}"
parallel -j1 -d , echo ::: "$var1"
parallel -j1 echo ::: $var2
-j1
は、一度に1つのジョブを強制的に実行します。
コードに構文エラーがあります。 loop
関数の呼び出しで、"${arr[@]}"
を使用して、arr
配列を、個別に引用された各要素のリストに展開します。これは、表示するfor
ループで行うことであり、関数を呼び出すときにも行う必要があります。
loop echo "${arr[@]}"
また、関数は渡すコマンドの名前を選択する必要があり、残りの引数をループする必要があることにも注意してください。
loop () {
local cmd=$1; shift
for arg do
"$cmd" "$arg"
done
}
ここでは、最初の引数を変数cmd
(これはコマンドです)に割り当て、次に引数のリストからこの引数をshift
します。引数のリストには、ループしたい文字列のみが含まれています。
次に、ループは残りの各引数のコマンドを順番に呼び出します。
これはxargs
ユーティリティの目的を限られた方法で複製し、関数はこのユーティリティを使用して再実装できます(ただし、引数の1つに改行が埋め込まれていることが予想される場合を除きます)。オプションをxargs
に微調整するには:)
loop () {
local cmd=$1; shift
printf '%s\n' "$@" | xargs -L 1 "$cmd"
}
xargs
ユーティリティはデータが標準入力を介して配信されることを想定しているため、printf
を使用してこれを調整し、loop
に指定された各引数を独自の行に出力します( xargs
は、-L 1
)を使用して、改行で区切られた引数ごとに1回、指定されたユーティリティを呼び出します。
これにより、-P n
を使用して並列プロセスを開始するなど、xargs
のいくつかの実装の他の機能を使用できるようになります。ここで、n
は並列で実行するプロセスの数です。
テスト:
$ cat script.sh
loop () {
local cmd=$1; shift
printf '%s\n' "$@" | xargs -L 1 "$cmd"
}
arr1=(1 2 3)
arr2=("hello world" "home sweet home")
loop echo "${arr1[@]}"
loop echo "${arr2[@]}"
$ bash script.sh
1
2
3
hello world
home sweet home