
以下をエクスポートするユーティリティを実行しています。
- 標準誤差の進行
- データ/出力/出力を標準出力に
私はユーティリティを構築しておらず、簡単に修正することはできません。
私は次のことをしたいと思います:
- 標準エラーを送信まっすぐ標準出力
- バッファリングする出力、標準出力にフラッシュコマンドが終了すると
(ここではデータが10KiB未満である可能性があるため、RAMは問題になりません。)
POSIX shでこれを行うことはできますか(そしてLinux共通ユーティリティを呼び出すだけです)そしてOpenBSD)、名前付きパイプや一時ファイルによって引き起こされる不確実性/潜在的な競合条件などはありませんか?
答え1
次のことができる必要があります。
{
cmd 2>&3 3>&- |
awk ' {saved = saved $0 ORS}
END {printf "%s", saved}' 3>&-
} 3>&1
awk
これはすべての出力を保存するために使用されますcmd
(cmd
stderr出力をスクリプトのstdoutに書き込んだ後)。
awk
パイプの書き込み端が閉じるまで読みます。通常、cmd
これはパイプのfdをまだ保持しているすべての分岐プロセスが完了した場合にのみ発生します。何らかの理由でcmd
stdoutを明示的に閉じてstderrに追加の進捗状況を記録することを決定した場合は、追加の進捗状況が表示されることがあります。後ろに通常出力。このサブシェル(パイプの標準出力も開いています)が完了するのを待つ場所と、そのサブシェルが完了するのを正確に待機する場所(および終了ステータスを報告する場所)を置き換えることで、cmd
この問題を解決できます。あります。(cmd; exit)
awk
cmd
exit
しかし、行動の良い人にはこれは必要ありませんcmd
。これはまた、スクリプトが完了してから長い間、またはスクリプトが完了した後でさえ(おそらく次の古いコマンドを使用して)stderrに書き込むことができるサブcmd
プロセスとそのstdoutリダイレクトをフォーク(待たずに)する場合も解決しません。awk
明示的な終了)可能性が高い)標準出力)。
cmd
出力がテキストでない場合、すべてのawk
実装がバイト0または非常に長い行を処理できるわけではなく、入力にまだない場合は改行が最後に追加されます。
POSIX ツールボックスには、メモリにランダムな量のバイナリデータを保存し、後で表示するコマンドはありません。
利用可能な場合は、コマンドをに置き換えるperl
ことができます。awk
perl -0777 -pe ''
ここでは、出力をメモリの代わりに一時ファイルに保存できます。これにより、バイナリ出力の問題が解決され、より大きな出力にさらに拡張できます。
残念ながら、一時ファイルを確実に生成する唯一のPOSIX方法は、このm4
ユーティリティを使用することです。このユーティリティは、今日の運用システム(POSIX必須システムでも)では常に見つかりません。perl
より見つける可能性が高いかもしれませんm4
。
とにかく、これは次のようになります。
die() {
[ "$#" -eq 0 ] || printf >&2 '%s\n' "$@"
exit 1
}
tmpdir=${TMPDIR:-/tmp}
tmpfile=$(
echo 'mkstemp(TEMPLATE)' |
m4 -D "TEMPLATE=${tmpdir%/}/XXXXXXX"
) && [ -n "$tmpfile" ] || die 'Cannot get a temp file'
{
rm -f -- "$tmpfile" || die "Cannot remove $tmpfile"
cmd 2>&1 >&3 3>&- 4<&-
cat <&4
} 3> "$tmpfile" 4< "$tmpfile"
ここでは、一時ファイルを開いた後に実行する前にリンクを解除するcmd
ことがクリーンアップを処理するきちんとした方法です。
GNU(「Linux」はオペレーティングシステムではなく、さまざまなオペレーティングシステムで見つかるカーネルだけであり、一部は1つもない場合もあります)とOpenBSDシステムのみを対象とする場合は、一時ファイルを生成できるはずです。sh
を使用して 。mktemp
m4
答え2
#!/bin/bash
mycmd() {
echo progress >&2
echo out
sleep 1
echo progress >&2
echo out
sleep 1
echo progress >&2
echo out
sleep 1
}
# Make sure the tempfile is made in a secure way that avoids indeterminism / potential race conditions / etc.
tmpfile="$(tempfile)"
# Write output to the file
mycmd 2>&1 >"$tmpfile"; cat "$tmpfile"; rm "$tmpfile"
# or if output is small: Write it to an environment variable.
# These are below the limit for "small" for different shells
# (Determined by making "mycmd" output that amount of data)
# ash 30 GB
# dash 30 GB
# bash 3 GB
# zsh 3 GB
# ksh 1 GB
out=`mycmd` 2>&1
echo "$out"
どちらのソリューションもルート(ファイルシステムと/ proc / * / environ)に表示され、システムの他のユーザーには表示されません。
システムにsponge
/dev/stdoutがあり、シェルがそれをサポートしている場合:
{
cmd 2>&3 3>&- |
sponge /dev/stdout 3>&-;
} 3>&1
(Kshバージョン:
$ ksh --version
version sh (AT&T Research) 93u+ 2012-08-01
)