Chuyển hướng STDERR / STDOUT của một quá trình SAU KHI nó đã được bắt đầu, sử dụng dòng lệnh?


127

Trong shell bạn có thể thực hiện chuyển hướng > <, v.v., nhưng SAU KHI chương trình được bắt đầu thì sao?

Đây là cách tôi đến để hỏi câu hỏi này, một chương trình chạy trong nền của thiết bị đầu cuối của tôi tiếp tục xuất ra văn bản gây phiền nhiễu. Đây là một quá trình quan trọng vì vậy tôi phải mở một shell khác để tránh văn bản. Tôi muốn có thể >/dev/nullhoặc một số chuyển hướng khác để tôi có thể tiếp tục làm việc trong cùng một vỏ.


Tôi biết cách dễ nhất để chuyển hướng STDOUT / STDERR là DUP2 mô tả tệp của họ TRƯỚC KHI. Đây là một thực hành khá chuẩn, và có lẽ là cách đạn pháo hoàn thành nó ngay bây giờ. Không chắc chắn nếu điều đó đưa ra một câu trả lời, nhưng tôi nghĩ rằng nó làm giảm cơ hội có một người tốt.
Stefan Mai

Câu trả lời:


124

Không đóng và mở lại tty của bạn (tức là đăng xuất và bật lại, điều này cũng có thể chấm dứt một số quy trình nền của bạn trong quy trình), bạn chỉ còn một lựa chọn:

  • đính kèm vào quy trình được đề cập bằng gdb và chạy:
    • p dup2 (mở ("/ dev / null", 0), 1)
    • p dup2 (mở ("/ dev / null", 0), 2)
    • tách ra
    • bỏ

ví dụ:

$ 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

Bạn cũng có thể xem xét:

  • sử dụng screen; màn hình cung cấp một số TTY ảo mà bạn có thể chuyển đổi giữa mà không cần phải mở SSH / telnet / etc, phiên mới
  • sử dụng nohup; điều này cho phép bạn đóng và mở lại phiên của mình mà không mất bất kỳ quy trình nền nào trong ... quy trình.

1
Câu trả lời gdb của bạn không hoạt động với tệp đuôi -f và nó không hoạt động với chương trình thử nghiệm trong c được biên dịch với gcc -ggdb, một printf mỗi giây. Ngoài ra cont làm cho không thể chạy nhiều lệnh gdb hơn, lệnh sẽ được tách ra, sau đó thoát.
Ian Kelling

Đúng về tách ra, đó là 2 giờ sáng. :) Chính xác thì cái gì không hoạt động với giải pháp gdb?
vladr

12
Nếu bạn đang chuyển hướng stdout / stderr (sang bất cứ thứ gì ngoài / dev / null rõ ràng), bạn cần mở tệp với quyền truy cập ghi - open("/path/to/new/stdout",O_WRONLY). O_WRONLY có lẽ sẽ không có sẵn, mặc dù; giá trị của nó là 1trên Linux / glibc.
Jander

13
Một lời cảnh báo: việc gắn vào một quy trình trong gdb sẽ tạm dừng quá trình cho đến khi bạn tách ra khỏi nó.
Marty B

1
Thêm vào nhận xét của @Jander, sử dụng 1025kích hoạt O_APPENDthêm vào O_WRONLY, sẽ rất hữu ích nếu bạn chuyển hướng cả stderr và stdout vào cùng một tệp.
quang phổ

57

Điều này sẽ làm:

strace -ewrite -p $PID

Nó không sạch sẽ (hiển thị các dòng như write(#,<text you want to see>):), nhưng hoạt động!


Bạn cũng có thể không thích thực tế là các đối số được viết tắt. Để kiểm soát việc sử dụng -stham số đặt độ dài tối đa của chuỗi được hiển thị.

Nó bắt tất cả các luồng, vì vậy bạn có thể muốn lọc bằng cách nào đó:

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

chỉ hiển thị mô tả 1 cuộc gọi. 2>&1là để chuyển hướng STDERR sang STDOUT, như straceghi vào STDERR theo mặc định.


6
Đây không phải là những gì OP yêu cầu. OP yêu cầu GIẢM GIÁ từ TTY, không đánh chặn. Ngoài ra, trên một số nền tảng, strace / giàn sẽ chèn khoảng trắng giữa các ký tự luồng bị chặn và / hoặc thoát khỏi ASCII và bạn cũng sẽ phải xử lý các xử lý đó.
vladr

4
Vâng, điều này thực hiện một phần - nhưng đối với một số người đọc câu hỏi này, đó là tất cả những gì họ cần - để xem những gì đang xảy ra trong một chương trình chạy nhầm sang ghi vào null hoặc trên bảng điều khiển khác. Tôi đã tìm ra nó sau khi tìm thấy câu hỏi này trong quá trình và nghĩ rằng đó là một bản hack hay (ít nhất là đối với tôi). VÀ khá nhiều người thấy hữu ích nếu mắt tôi không từ chối tôi;)
naugtur

Nó cũng có thể sudolà cần thiết.
colidyre

21

riff off vladr (và những người khác) nghiên cứu xuất sắc:

tạo hai tệp sau trong cùng một thư mục, một cái gì đó trong đường dẫn của bạn, giả sử $ HOME / bin:

quiet.gdb, có chứa (từ câu trả lời của vladr):


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

và im lặng, chứa:


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

Bây giờ, lần tới khi bạn quên chuyển hướng firefox, chẳng hạn, và thiết bị đầu cuối của bạn bắt đầu lộn xộn với các thông điệp không thể tránh khỏi "(firefox-bin: 5117): Gdk-CẢNH BÁO **: XID va chạm, rắc rối phía trước":


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

Bạn cũng có thể chuyển hướng đầu ra của gdb thành / dev / null nếu bạn không muốn xem nó.


3
Gdb của tôi (v7.2) có một tùy chọn tiện dụng --batch-silentgiúp triệt tiêu đầu ra và không đưa bạn vào bảng điều khiển gdb nếu có sự cố xảy ra (ví dụ: thiếu quy trình). BTW, $!đề cập đến công việc nền gần đây nhất, nhưng tôi không nghĩ rằng nó có thể được sử dụng trong chính kịch bản. Tôi sử dụng một bí danh: alias silencebg='silence $!'
seanf

18

Chuyển hướng đầu ra từ một quá trình đang chạy sang thiết bị đầu cuối, tệp hoặc màn hình khác:

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

Bên trong gdb :

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

Tách một quy trình đang chạy từ thiết bị đầu cuối bash và giữ cho nó sống:

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

Giải trình:

20818 - chỉ là một ví dụ về quá trình chạy pid
p - kết quả in của lệnh gdb
đóng (1) - đóng đầu ra tiêu chuẩn
/ dev / pts / 4 - terminal để ghi để
đóng (2) - đóng lỗi đầu ra
/ tmp / myerrlog - tệp vào ghi vào
q - thoát gdb
bg% 1 - chạy công việc đã dừng 1 trên nền bị
từ chối% 1 - tách công việc 1 khỏi thiết bị đầu cuối


2
Điều này sẽ không hoạt động nếu stdin(mô tả tập tin 0) được đóng lại.
pabouk

Điều này đã cứu ngày của tôi. Tôi đã có một lần thực hiện trong một phiên ssl mất 10 giờ cho 10% đầu tiên và tôi thực sự không muốn giữ máy tính xách tay của mình chạy thêm 10 giờ nữa. Nhưng tôi có đúng không khi cho rằng chuyển hướng của bạn cho stderr nên đọc p open("/tmp/myerrlog", 2)?
GerardV

Có một vấn đề rất nhỏ với vấn đề này khi chạy trên CentOS 6 - tệp "/ tmp / myerrlog" đã tồn tại. Dĩ nhiên, việc tạo ra nó bằng cảm ứng là chuyện nhỏ.
ebneter

3

Không phải là câu trả lời trực tiếp cho câu hỏi của bạn, nhưng đó là một kỹ thuật tôi đã thấy hữu ích trong vài ngày qua: Chạy lệnh ban đầu bằng cách sử dụng 'màn hình', rồi tách ra.


2

đây là phần bash script dựa trên các câu trả lời trước đó, nó chuyển hướng tệp nhật ký trong khi thực hiện quy trình mở, nó được sử dụng làm phần tái bút trong logrotatequá trình

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

Bạn có thể sử dụng reredirect ( https://github.com/jerome-pouiller/reredirect/ ).

Kiểu

reredirect -m FILE PID

và đầu ra (tiêu chuẩn và lỗi) sẽ được viết trong TẬP TIN.

reredirect README cũng giải thích cách khôi phục trạng thái ban đầu của quy trình, cách chuyển hướng đến một lệnh khác hoặc chỉ chuyển hướng thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn.

reredirectcũng cung cấp một tập lệnh được gọi là relinkcho phép chuyển hướng đến thiết bị đầu cuối hiện tại:

relink PID
relink PID | grep usefull_content

(reredirect dường như có các tính năng tương tự như Dupx được mô tả trong một câu trả lời khác, nhưng, nó không phụ thuộc vào Gdb).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.