Bir işlemin STDERR / STDOUT'u, başlatıldıktan SONRA komut satırı kullanarak yeniden yönlendirilsin mi?


127

Kabukta yeniden yönlendirme > <vb. Yapabilirsiniz , ancak bir program başlatıldıktan SONRA ne dersiniz?

Bu soruyu şu şekilde sormaya başladım, terminalimin arka planında çalışan bir program rahatsız edici metinler üretmeye devam ediyor. Bu önemli bir işlem, bu yüzden metinden kaçınmak için başka bir kabuk açmam gerekiyor. >/dev/nullAynı kabukta çalışmaya devam edebilmek için başka bir yönlendirme veya başka bir yönlendirme yapmak istiyorum.


STDOUT / STDERR'yi yeniden yönlendirmenin en kolay yolunun, çatallanmadan ÖNCE dosya tanımlayıcılarını DUP2'ye geçirmek olduğunu biliyorum. Bu oldukça standart bir uygulamadır ve muhtemelen mermilerin bunu şu anda başarma şeklidir. Bunun bir cevap verip vermediğinden emin değilim, ama iyi bir cevap olma şansını azalttığını düşünüyorum.
Stefan Mai

Yanıtlar:


124

Tty'nizi kapatıp yeniden açmanın (yani, işlemdeki bazı arka plan işlemlerinizi sonlandırabilen oturum kapatıp tekrar açmanız) kısa bir süre için geriye yalnızca bir seçeneğiniz kaldı:

  • gdb'yi kullanarak söz konusu işleme ekleyin ve çalıştırın:
    • p dup2 (açık ("/ dev / null", 0), 1)
    • p dup2 (açık ("/ dev / null", 0), 2)
    • ayırmak
    • çıkmak

Örneğin:

$ 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

Ayrıca şunları da düşünebilirsiniz:

  • kullanarak screen; ekran, yeni SSH / telnet / vb. oturumları açmak zorunda kalmadan aralarında geçiş yapabileceğiniz birkaç sanal TTY sağlar
  • kullanarak nohup; bu, ... işlemindeki arka plan işlemlerini kaybetmeden oturumunuzu kapatmanıza ve yeniden açmanıza olanak tanır.

1
Gdb cevabınız tail -f dosyasıyla çalışmadı ve her saniye printf yapan gcc -ggdb ile derlenmiş c'deki bir test programıyla da çalışmadı. Ayrıca cont, daha fazla gdb komutunun çalıştırılmasını imkansız kılar, komut önce ayrılıp sonra çıkılır.
Ian Kelling

Ayrılma hakkında doğru, saat 02:00. :) gdb çözümüyle tam olarak ne işe yaramadı?
vladr

12
Stdout / stderr'i (görünüşte / dev / null dışında herhangi bir şeye) yönlendiriyorsanız, dosyayı yazma erişimiyle açmanız gerekir - open("/path/to/new/stdout",O_WRONLY). O_WRONLY muhtemelen mevcut olmayacak; değeri 1Linux / glibc üzerindedir.
Jander

13
Bir uyarı: gdb'deki bir işleme eklemek, siz ondan ayrılıncaya kadar süreci duraklatır.
Marty B

1
@Jander'ın yorumuna ek olarak , 1025etkinleştirirleri kullanarak , hem stderr hem de stdout'u aynı dosyaya yeniden yönlendirirseniz kullanışlıdır. O_APPENDO_WRONLY
spectras

57

Bu yapacak:

strace -ewrite -p $PID

O kadar temiz değil (gibi satırlar gösteriyor:) write(#,<text you want to see>), ama işe yarıyor!


Ayrıca argümanların kısaltılmış olmasından da hoşlanmayabilirsiniz. Bunu kontrol etmek için, -sgörüntülenen maksimum dizi uzunluğunu ayarlayan parametreyi kullanın .

Tüm akışları yakalar, bu nedenle bunu bir şekilde filtrelemek isteyebilirsiniz:

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

yalnızca tanımlayıcı 1 çağrılarını gösterir. 2>&1STDERR'yi STDOUT'a yönlendirmek, stracevarsayılan olarak STDERR'ye yazdığı gibi .


6
Bu, OP'nin istediği şey değil. OP, engellemeyi değil, TTY'den uzakta YÖNLENDİRME istedi. Ayrıca, bazı platformlarda strace / truss, kesilen akım karakterleri arasına boşluklar ekler ve / veya ASCII olmayan kaçış yapar ve bunları işlemekle de uğraşmanız gerekir.
vladr

4
Evet, bu işi kısmen yapar - ama bu soruyu okuyan bazı insanlar için tek ihtiyaç duydukları şey bu - yanlışlıkla boşa veya başka bir konsola yazmak için çalıştırılan bir programda neler olduğunu görmek. Süreçte bu soruyu bulduktan sonra öğrendim ve bunun güzel bir hack olduğunu düşündüm (en azından benim için). VE gözlerim beni
kandırmazsa,

sudoİhtiyaç duyulması da mümkündür .
colidyre

21

vladr'ın (ve diğerlerinin) mükemmel araştırmasını bozmak:

aynı dizinde aşağıdaki iki dosyayı oluşturun, yolunuzdaki bir şey, diyelim ki $ HOME / bin:

silence.gdb, şunları içeren (vladr'ın cevabından):


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

ve sessizlik, şunları içerir:


#!/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

Şimdi, örneğin bir dahaki sefere firefox'u yeniden yönlendirmeyi unuttuğunuzda ve terminaliniz kaçınılmaz "(firefox-bin: 5117): Gdk-WARNING **: XID çarpışması, sorun devam ediyor" mesajlarıyla darmadağın olmaya başlar:


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

Ayrıca gdb'nin çıktısını görmek istemiyorsanız / dev / null'a yeniden yönlendirebilirsiniz.


3
Benim gdb'm (v7.2) --batch-silentçıktıyı bastıran ve bir şeyler ters giderse (örn. Eksik süreç) sizi gdb konsoluna atmayan kullanışlı bir seçeneğe sahiptir. BTW, $!en son arka plan işini ifade ediyor, ancak betiğin kendisinde kullanılabileceğini düşünmüyorum. Bir takma ad kullanıyorum: alias silencebg='silence $!'
seanf

18

Çıktıyı çalışan bir işlemden başka bir terminale, dosyaya veya ekrana yönlendirin:

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

Çalışan bir işlemi bash terminalinden ayırın ve canlı tutun:

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

Açıklama:

20818 - çalıştırma işleminin sadece bir örneği pid
p - gdb komutunun sonucunu yazdır
close (1) - standart çıktıyı kapat
/ dev / pts / 4 -
kapatmak için terminal (2) - hata çıktısını kapat
/ tmp / myerrlog - dosya yazma
q - Pes gdb
bg% 1 - run arka plan üzerinde iş 1 stoped
uçbirimini işinin 1 - disown% 1


2
Bu işe yaramaz stdin(dosya tanıtıcı 0) kapalıdır.
pabouk

Bu günümü kurtardı. İlk% 10 için bir saat süren bir ssl oturumunda çalışan bir makyaj yaptım ve dizüstü bilgisayarımı bir 10 saat daha çalışır durumda tutmak istemedim. Ama stderr için yeniden yönlendirmenizin okunması gerektiğini varsaymakta haklı p open("/tmp/myerrlog", 2)mıyım?
GerardV

CentOS 6'da bu çalışmayla ilgili çok küçük bir sorun vardı - "/ tmp / myerrlog" dosyası zaten mevcut olmalıydı. Elbette dokunarak yaratmak önemsizdi.
ebneter

3

Sorunuza doğrudan bir cevap değil, ancak son birkaç gündür faydalı bulduğum bir teknik: 'screen' kullanarak ilk komutu çalıştırın ve ardından ayırın.


2

Bu açık bir sürecin yürütülmesi sırasında günlük dosyasını yeniden yönlendirmek önceki cevaplar dayalı bash komut parçasıdır, içeri postscript olarak kullanılan logrotatesüreç

#!/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

Yeniden yönlendirmeyi kullanabilirsiniz ( https://github.com/jerome-pouiller/reredirect/ ).

tip

reredirect -m FILE PID

ve çıktılar (standart ve hata) DOSYA olarak yazılacaktır.

yeniden yönlendirme README ayrıca orijinal işlem durumunun nasıl geri yükleneceğini, başka bir komuta nasıl yönlendirileceğini veya yalnızca stdout veya stderr'in nasıl yönlendirileceğini açıklar.

reredirectayrıca relinkmevcut terminale yönlendirmeye izin veren bir komut dosyası sağlayın :

relink PID
relink PID | grep usefull_content

(yeniden yönlendirme başka bir cevapta açıklanan Dupx ile aynı özelliklere sahip gibi görünüyor, ancak Gdb'ye bağlı değil).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.