コマンドラインを使用して、プロセスの開始後にSTDERR / STDOUTをリダイレクトしますか?


127

シェルではリダイレクト> <などを行うことができますが、プログラムが開始された後はどうですか?

これが私がこの質問をするようになった方法です。私の端末のバックグラウンドで実行されているプログラムが迷惑なテキストを出力し続けます。これは重要なプロセスなので、テキストを回避するために別のシェルを開く必要があります。>/dev/null同じシェルで作業を続けることができるように、他のリダイレクトができるようにしたいと思います。


STDOUT / STDERRをリダイレクトする最も簡単な方法は、フォークする前にファイル記述子をDUP2することです。これはかなり標準的な方法であり、おそらくシェルが現在それを達成する方法です。それが答えを与えるかどうかはわかりませんが、良いものがある可能性が減ると思います。
ステファンマイ

回答:


124

ttyを閉じて再度開く(つまり、ログオフして再度ログオンすると、プロセス内のバックグラウンドプロセスの一部が終了する可能性があります)以外の選択肢は1つだけです。

  • gdbを使用して問題のプロセスにアタッチし、実行します。
    • p dup2(open( "/ dev / null"、0)、1)
    • p dup2(open( "/ dev / null"、0)、2)
    • 切り離す
    • 終了する

例えば:

$ tail -f /var/log/lastlog &
[1] 5636

$ ls -l /proc/5636/fd
total 0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/pts/0
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog

$ gdb -p 5636
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Attaching to process 5636
Reading symbols from /usr/bin/tail...(no debugging symbols found)...done.
Reading symbols from /lib/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/librt.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
[New Thread 0x7f3c8f5a66e0 (LWP 5636)]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2

(no debugging symbols found)
0x00007f3c8eec7b50 in nanosleep () from /lib/libc.so.6

(gdb) p dup2(open("/dev/null",0),1)
[Switching to Thread 0x7f3c8f5a66e0 (LWP 5636)]
$1 = 1

(gdb) p dup2(open("/dev/null",0),2)
$2 = 2

(gdb) detach
Detaching from program: /usr/bin/tail, process 5636

(gdb) quit

$ ls -l /proc/5636/fd
total 0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/null
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/null
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog
lr-x------ 1 myuser myuser 64 Feb 27 07:36 4 -> /dev/null
lr-x------ 1 myuser myuser 64 Feb 27 07:36 5 -> /dev/null

次のことも検討してください。

  • を使用して screen ; 画面には、新しいSSH / telnet / etc、セッションを開かなくても切り替えることができるいくつかの仮想TTYが表示されます
  • を使用してnohup; これにより、...プロセスのバックグラウンドプロセスを失うことなく、セッションを閉じて再度開くことができます。

1
gdbの答えはtail -fファイルでは機能せず、毎秒printfを実行するgcc -ggdbでコンパイルされたcのテストプログラムでも機能しませんでした。また、続きはそれ以上のgdbコマンドを実行することを不可能にします、コマンドは切り離され、そして終了します。
イアンケリング

デタッチについては正解です。午前2時です。:) gdbソリューションで正確に機能しなかったものは何ですか?
vladr 2009

12
stdout / stderrを(/ dev / null以外に明らかに)リダイレクトしている場合は、書き込みアクセスでファイルを開く必要があります- open("/path/to/new/stdout",O_WRONLY)。ただし、O_WRONLYはおそらく使用できません。その値は1Linux / glibcにあります。
ジャンダー

13
注意:gdbのプロセスにアタッチすると、デタッチするまでプロセスが一時停止します。
Marty B

1
@Janderのコメントに追加し、に加えて1025アクティベートO_APPENDを使用しO_WRONLYます。これは、stderrとstdoutの両方を同じファイルにリダイレクトする場合に便利です。
2016年

57

これは行います:

strace -ewrite -p $PID

それほどきれいではありませんが(次のような行が表示されますwrite(#,<text you want to see>))、機能します!


引数が省略されているという事実も嫌いかもしれません。それを制御するには、-s表示される文字列の最大長を設定パラメーターます。

それはすべてのストリームをキャッチするので、なんとかしてそれをフィルタリングしたいかもしれません:

strace -ewrite -p $PID 2>&1 | grep "write(1" 

は、記述子1の呼び出しのみを示しています。デフォルトではSTDERRに書き込むため2>&1、STDERRをSTDOUTにリダイレクトstraceします。


6
これはOPが要求したものではありません。OPは、インターセプトではなく、TTYから離れてリダイレクトするように要求しました。また、一部のプラットフォームでは、strace / trussは、インターセプトされたストリーム文字の間にスペースを挿入したり、非ASCIIをエスケープしたりするため、それらも処理する必要があります。
vladr

4
はい、これは部分的に機能します。ただし、この質問を読む人によっては、nullまたは別のコンソールに書き込むために誤って実行されるプログラムで何が起こっているのかを確認するために必要なすべてです。プロセスでこの質問を見つけた後、私はそれを発見し、それは(少なくとも私にとっては)良いハックだと思いました。そして、かなりの数の人が、私の目が私をだましていない場合に役立つと感じています;)
naugtur

それsudoが必要になることも可能です。
コリディア

21

vladr(および他の人)の優れた研究を追い払う:

同じディレクトリに次の2つのファイルを作成します。たとえば、パスに$ HOME / binを指定します。

silence.gdbを含む(vladrの回答から):


p dup2(open("/dev/null",0),1)
p dup2(open("/dev/null",0),2)
detach
quit

そして沈黙、含む:


#!/bin/sh
if [ "$0" -a "$1" ]; then
 gdb -p $1 -x $0.gdb
else
 echo Must specify PID of process to silence >&2
fi

chmod +x ~/bin/silence  # make the script executable

たとえば、次にfirefoxをリダイレクトするのを忘れたときなど、端末が不可避の「(firefox-bin:5117):Gdk-WARNING **:XID衝突、トラブルアヘッド」というメッセージで乱雑になり始めます。


ps  # look for process xulrunner-stub (in this case we saw the PID in the error above)
silence 5117  # run the script, using PID we found

表示したくない場合は、gdbの出力を/ dev / nullにリダイレクトすることもできます。


3
私のgdb(v7.2)には便利なオプションが--batch-silentあり、出力を抑制し、何かがうまくいかない場合(たとえば、プロセスが見つからない場合)にgdbコンソールにダンプしません。ところで、$!最新のバックグラウンドジョブを指しますが、スクリプト自体では使用できないと思います。私はエイリアスを使用します:alias silencebg='silence $!'
seanf

18

実行中のプロセスからの出力を別の端末、ファイル、または画面にリダイレクトします。

tty
ls -l /proc/20818/fd
gdb -p 20818

内部gdb

p close(1)
p open("/dev/pts/4", 1)
p close(2)
p open("/tmp/myerrlog", 1)
q

実行中のプロセスをbashターミナルから切り離し、それを存続させます。

[Ctrl+z]
bg %1 && disown %1
[Ctrl+d]

説明:

20818-実行中のプロセスの例pid
p-gdbコマンドの結果を
出力するclose(1)-標準出力を閉じる
/ dev / pts / 4-
close に書き込むターミナル(2)-エラー出力を閉じる
/ tmp / myerrlog-ファイル
q への書き込み -gdb
bg%1を終了します-バックグラウンドの
破棄%1で停止したジョブ1を実行します-ジョブ1を端末から切り離します


2
stdin(ファイル記述子0)が閉じている場合、これは機能しません。
pabouk 2014年

これは私の日を救った。最初の10%は1時間かかるsslセッションでmakeを実行していましたが、ラップトップをさらに10時間実行し続けたくありませんでした。しかし、私はstderrのリダイレクトを読むべきだと p open("/tmp/myerrlog", 2)思いますか?
GerardV 2016年

CentOS 6での実行に非常に小さな問題がありました。「/ tmp / myerrlog」ファイルはすでに存在している必要がありました。もちろん、タッチで作成するのは簡単でした。
ebneter 2018年

3

あなたの質問への直接の答えではありませんが、それは私が過去数日間にわたって有用であると私が見つけてきたテクニックです: 'screen'を使用して最初のコマンドを実行し、次にデタッチします。


2

これは、以前の回答に基づくbashスクリプトの一部であり、オープンプロセスの実行中にログファイルをリダイレクトします。これは、logrotateプロセスのポストスクリプトとして使用されます

#!/bin/bash

pid=$(cat /var/run/app/app.pid)
logFile="/var/log/app.log"

reloadLog()
{
    if [ "$pid" = "" ]; then
        echo "invalid PID"
    else
        gdb -p $pid >/dev/null 2>&1 <<LOADLOG
p close(1)
p open("$logFile", 1)
p close(2)
p open("$logFile", 1)
q
LOADLOG
        LOG_FILE=$(ls /proc/${pid}/fd -l | fgrep " 1 -> " | awk '{print $11}')
        echo "log file set to $LOG_FILE"
    fi
}

reloadLog


0

reredirect(https://github.com/jerome-pouiller/reredirect/)を使用できます。

タイプ

reredirect -m FILE PID

出力(標準およびエラー)はFILEに書き込まれます。

reredirect READMEは、プロセスの元の状態を復元する方法、別のコマンドにリダイレクトする方法、またはstdoutまたはstderrのみをリダイレクトする方法についても説明しています。

reredirectrelink現在の端末にリダイレクトできるようにするというスクリプトも提供します。

relink PID
relink PID | grep usefull_content

(リダイレクトは別の回答で説明されているDupxと同じ機能を持っているようですが、Gdbには依存しません)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.