/dev/nullにリダイレクトされたstd出力を取得する方法はありますか?試してみましたが、tail -f /proc/{PID}/fd/1
リダイレクト以外は機能しているようです/dev/null
。
つまり
tail -f /proc/${cmd_pid}/fd/1
有効cmd > log.txt
だが無効cmd > /dev/null
- - - - - - - 更新 - - - - - - -
実際、log.txt
stdoutが常に記録されている場合、大きな問題が発生します。プロセス自体を停止せずにロギングまたはロギングを停止するタイミングを制御できる場合は、これがcmd
最善です。
tmp
もしそうなら、stdoutをリソース集約的でないいくつかのファイルシステムにリダイレクトし、必要に応じてstdoutを検索できますか?
答え1
これにより、cmd > /dev/null
シェルは新しいサブプロセスでfd 1を開き、/dev/null
それを実行しますcmd
。
cmd
fdが何に開いているかに関係なく、stdout(または、またはwrite(1, "output"...)
などの他の書き込みシステム呼び出し)にデータを書き込むことを行います。send
sendmsg
pwrite
Linuxでは、fd 1ファイルが開くマジック/proc/$pid_of_cmd/fd/1
シンボリックリンクのみがあるため。/dev/null
tail -f that
tail -f /dev/null
これらのwrite()
システムコールを傍受してstrace
結果をデコードできます。
strace -zqqs99999 -xxa0 -o /dev/stdout -e write -p "$pid" |
perl -ne 'print chr(hex($_)) for /\\x(..)/g'
または:
strace -zqqs99999 -xxa0 -o /dev/stdout -e write -p "$pid" |
perl -ne 'if (/^write\(1,/) {print chr(hex($_)) for /\\x(..)/g}'
write()
sからstdout(fd 1)にのみ適用されます。または:
strace -yzqqs99999 -xxa0 -o /dev/stdout -e write -p "$pid" |
perl -ne 'if (/^\Qwrite(1<\x2f\x64\x65\x76\x2f\x6e\x75\x6c\x6c>,\E "(.*)"/) {
print chr(hex($_)) for $1 =~ /\\x(..)/g}'
sでstdout(fd 1)にのみ適用され、write()
stdoutがで開いている場合にのみ適用されます/dev/null
。
出力をttyデバイス以外のデバイスにリダイレクトすると、行ではなくperl
ブロック単位でバッファリングが開始されるため、大量に数KBの出力しか表示されません。$|
変数を次のように設定することで、このバッファリングを無効にできます1
。
strace -zqqs99999 -xxa0 -o /dev/stdout -e write -p "$pid" |
perl -ne 'BEGIN{$| = 1}
print chr(hex($_)) for /\\x(..)/g' > file
それともそうするのではなく、cmd > /dev/null
そうしてくださいcmd | cat > /dev/null
。
これでcmd
stdoutはパイプになり、Linuxでは/proc/$pid_of_cmd/fd/1
名前付きパイプのように動作します。そうすれば次のようになります。
kill -s STOP "$pid_of_cat"
cat "/proc/$pid_of_cmd/fd/1"
実際にパイプを新しいcat
コマンドにリダイレクトします。
新しいパイプを終了した場合は、cat
そのパイプのタブを再度開くには、別のパイプ()を復元する必要がありますkill -s CONT "$pid_of_cat"
。/dev/null
プロセスの標準出力位置を実際に変更するには、デバッガを接続できます。
gdb --pid "$pid_of_cmd"
その後、gdbで:
call close(1)
p open("/path/to/some/file", 0x241, 0600)
detach
(0x241はO_WRONLY | O_TRUNC | O_CREATを意味します)
open()
fd 1が返されることを確認してください。そうでない場合は、数回の通話dup2()
と追加が必要になることがありますclose()
。
答え2
いいえ、ファイルハンドルを変更できません。
それでは、stdoutをリソース集約的でないいくつかのtmpファイルシステムにリダイレクトし、必要に応じてstdoutを検索できますか?
いいえ、データを保存しないとデータを保存できません。どこかに。
誰かが循環バッファを作成した可能性があります。これにより、最後の100,000個のデータを表示できます。または、プログラムが通常ヘッドなしで実行されている場合は、出力を画面に送信してから実行できますscreen
。
答え3
検索しないとstdoutが削除され、検索を開始するとstdoutがログファイルにリダイレクトされる可能性があります。
これは、次のように出力をシェルスクリプトにパイプすることで実行できます。
#! /bin/sh
# a-script.sh
while IFS= read -d input
do
printf "%s\n" input >> /some/file
done
特に、各反復で出力ファイルを再度開くために、リダイレクトがループ内で行われます。それから始めなさい。
ln -s /dev/null /some/file
cmd | a-script.sh
その後、ログが欲しいとき:
ln -sf /some/log/file /some/file
ループの次の繰り返しは、/some/log/file
toの代わりに書き込みを開始します/dev/null
。
コマンドが大量に記録されると、重大なパフォーマンス低下が発生する可能性があります。