コマンド置換の結果を使用して、いくつかの環境変数を設定しようとしています。 &
およびwait
と並行してコマンドを実行したいと思います。私が現在持っているものは次のようになります
export foo=`somecommand bar` &
export fizz=`somecommand baz` &
export rick=`somecommand morty` &
wait
しかし、どうやら&
を使用する場合、変数の割り当ては固執しません。したがって、wait
の後、これらの変数はすべて割り当て解除されます。
これらの変数を並行して割り当てるにはどうすればよいですか?
更新:これは、受け入れられた回答に基づいて私が最終的に使用したものです
declare -a data
declare -a output
declare -a processes
var_names=(
foo
fizz
rick
)
for name in "${var_names[@]}"
do
processes+=("./get_me_a_value_for $name")
done
index=0
for process in "${processes[@]}"; do
output+=("$(mktemp)")
${process} > ${output[$index]} &
index=$((index+1))
done
wait
index=0
for out in "${output[@]}"; do
val="$(<"${out}")"
rm -f "${out}"
export ${var_names[index]}="$val"
index=$((index+1))
done
unset data
unset output
unset processes
いくつかの反省の後、私は醜い回避策を思いつきました:
#!/bin/bash
proc1=$(mktemp)
proc2=$(mktemp)
proc3=$(mktemp)
/path/to/longprocess1 > "$proc1" &
pid1=$!
/path/to/longprocess2 > "$proc2" &
pid2=$!
/path/to/longprocess3 > "$proc3" &
pid3=$!
wait "$pid1" "$pid2" "$pid3"
export var1="<("$proc1")"
export var2="<("$proc2")"
export var3="<("$proc3")"
rm -f "$proc1" "$proc2" "$proc3"
コメントで要求されているように、これを任意の大きなリストに対してより拡張可能にする方法は次のとおりです。
#!/bin/bash
declare -a pids
declare -a data
declare -a output
declare -a processes
# Generate the list of processes for demonstrative purposes
processes+=("/path/to/longprocess1")
processes+=("/path/to/longprocess2")
processes+=("/path/to/longprocess3")
index=0
for process in "${processes[@]}"; do
output+=("$(mktemp")
$process > ${output[$index]} &
pids+=("$!")
index=$((index+1))
done
wait ${pids[@]}
index=0
for process in "${processes[@]}"; do
data+="$(<"${output[index]}")"
rm -f "${output[index]}"
index=$((index+1))
done
export data
結果の出力はdata
配列になります。
同時に安全に並行して実行できるよりも多くのジョブがある場合は、GNU Parallel:
i="$(parallel --files ::: "${cmd[@]}" | Perl -pe '$_="\"\`cat $_;rm $_\`\" "')"
eval my_result_array=($i)
unset i
または一般的に:
parset() {
local vname
vname="$1"
shift
if [[ "$(declare -p $vname 2>/dev/null)" =~ "declare -a" ]]; then
# vname refers to an array
# The array elements refers to variable names to put output into
eval $(
parallel --files "$@" |
Perl -pe 'chop;$_="\"\`cat $_; rm $_\`\"\n"' |
parallel echo {2}={1} :::: - :::+ $(eval echo '${'$vname'[@]}')
)
else
# vname is not an existing array: Put output into that
eval $vname="( $( parallel --files "$@" |
Perl -pe 'chop;$_="\"\`cat $_; rm $_\`\" "' ) )"
fi
}
# Put output into vars $seq, $pwd, $ls
into_vars=(seq pwd ls)
parset into_vars ::: "seq 10" pwd ls
echo "$ls"
# Put output into aaa
unset aaa
parset aaa seq 3 ::: 4 5 6
echo "${aaa[1]}"
# Output can contain spaces
parset out ::: "echo '<<joe \"double space\" cartoon>>'" "pwd"
echo "${out[0]}"
echo "${out[1]}"
# The commands to run can be an array
cmd=("echo '<<joe \"double space\" cartoon>>'" "pwd")
parset data ::: "${cmd[@]}"
echo "${data[0]}"
echo "${data[1]}"
# You cannot pipe into parset, but must use a tempfile
seq 10 > parallel_input
parset res echo :::: parallel_input
echo "${res[0]}"
echo "${res[9]}"