PostgresデータベースのデータをBashのファイルにエクスポートしようとしています。ただし、データベース接続が失敗しない場合にのみファイルを上書きしたい(たとえば、一部のデータを返す)。
試してみてくださいパイプ故障オプションですが、最初のコマンドがエラーのために失敗した場合(たとえば、ホストが存在しない場合)、catコマンドは引き続き実行され、空のファイルを生成します(保護したい最後の良い項目を消去します)。次の例では、myhostは無効なホストなので、psqlコマンドは失敗します。
したがって、大きな質問は、パイプ障害が設定されたときに最初のコマンドが失敗した場合に後続のコマンドが実行されないようにする方法です。
#!/bin/sh
set -o nounset
set -o errexit
set -o pipefail
PG_HOST=myhost
psql $PG_HOST -At -F$'\t' -c "SELECT * FROM mytable" | cat > /tmp/mytable.txt
ベストアンサー1
set -o pipefail -o errexit
後続のコマンドが実行されるのを防ぎますが、防止しようとしないため役に立ちません。フォローコマンドが実行されます。パイプラインでのproducer | consumer
実行producer
とconsumer
コマンド平行に。失敗した場合、異常なタイミング事故がない限り、すでに起動しているため、consumer
起動を防ぐことはできません。producer
2 つの可能性のみが「consumer
成功して非 null 出力を生成する」と「consumer
失敗して出力なしを生成」の場合は、次のようになります。ifne
Joey Hessのmoreutils。
producer | ifne consumer
私はこれがあなたのユースケースではうまくいかないと思います。一致する行がない可能性があり(肯定エラー、古いデータを取得)、データベース接続が途中で切断される可能性があります(肯定エラー、切り捨てられたデータを取得)。
生産者が成功したかどうかを知る必要がある場合は、消費者を開始する前に生産者が完了するのを待つ必要があります。消費者はまだ表示されていないため、出力を保存する必要があります。
出力にヌルバイトが含まれておらず、単一の改行文字で終わり、大きすぎない場合は、シェル変数に保存できます。
output=$(producer); producer_status=$?
if [ "$producer_status" -ne 0 ]; then
echo >&2 "Producer failed with status $producer_status"
exit "$producer_status"
fi
printf '%s\n' "$output" | consumer
zshや他のいくつかのシェル(ksh93とbashを含む)では、最後の行をconsumer <<<"$output"
。
コマンドの置き換えは末尾の改行を削除することに注意してください。末尾の空行が関連している場合、回避策は最初の行を次に変更することです。
output=$(producer; ret=$?; echo .; exit "$?")
producer_status=$? output=${output%?}
$output
これにより、末尾の改行文字(存在する場合)を含む完全な出力が含まれます。次に、提供するprintf %s "$output"
代わりに使用してください。printf '%s\n' "$output"
consumer
出力が大きすぎるかヌルバイトを含む可能性がある場合は、一時ファイルに保存してください。