複数の異なるサーバーに接続されたpostgresqlデータベースCLIの複数のインスタンスにコマンドをブロードキャストするために使用するこのようなスクリプトがあります。ハードコーディングされたプロセス交換セットを使用しています。
#!/bin/bash
# names have been changed to protect the guilty
cred="user=dbadmin password=SECRET"
domain=example.com
tee \
>( psql -X "host=db1.$domain dbname=db1 $cred" ) \
>( psql -X "host=db2.$domain dbname=db2 $cred" ) \
>( psql -X "host=db3.$domain dbname=db3 $cred" ) \
>( psql -X "host=xdb1.$domain dbname=xdb1 $cred" ) \
> /dev/null
wait
私がしたいのは、forループを使用して代替配列を作成し、次のようにその配列をteeに渡すことです。
tee "${p[@]}" > /dev/null
しかし、ループを使用すると、teeは各項目にエラーを提供するため、$p
各項目を取得します。/dev/fd/63
tee: /dev/fd/63: No such file or directory
動作しないコードの例:
p=()
for z in db1 db2 db3 xdb1
do
p+=( >( psql -X "host=$z.$domain dbname=$z $cred" ) )
done
tee "${p[@]}" > /dev/null
これを行う方法はありますか?
ベストアンサー1
これは次の行で発生します。
p+=( >( psql -X "host=$z.$domain dbname=$z $cred" ) )
...bashはこの行を完全なコマンドと見なします。プロセスの交換が発生すると、コマンドが完了すると交換されたプロセスのSTDINが閉じます。
私の考えでは、これを行う方法は2つしかありません。
eval
。そこに行かないでください。exec
。そこに行こう:
p=()
for z in db1 db2 db3 xdb1
do
exec {fd}> >(psql -X "host=$z.$domain dbname=$z $cred")
p+=( $fd )
done
cd /dev/fd && exec tee "${p[@]}" >/dev/null
この{fd}>
構文を使用すると、bashは新しいファイル記述子を割り当て、その値を割り当てて$fd
からそれをプッシュします$p
。
これで作成する$p
必要があるファイルディスクリプタ番号がたくさんあるので、ファイルディスクリプタ番号を実際のファイルに書き込んでから呼び出します。tee
cd
/dev/fd
tee
(猫が皮をむく方法はいくつかありますが、これが最初に浮かぶ最も簡単な方法です)