1

How do I redirect the output of a process run in bash (4.2.45(1)-release (x86_64-pc-linux-gnu)) stopped with SIGSTOP (usually sent with Strg+Z on Debian based and possibly other systems) and resumed with fg or bg. Consider the following example with things I've tried so far still printing output to console:

sudo apt-get update
# Strg+Z
fg > /dev/null 2>&1 # doesn't work
fg > /dev/null 2> /dev/null # doesn't work
fg > /dev/null # doesn't work

same with bg instead of fg

Please note that the question who to redirect output is already answered in Redirect all output to file.

Community
  • 1
  • 1
Kalle Richter
  • 8,008
  • 26
  • 77
  • 177
  • 2
    You don't, at least not easily or without using a debugger. Once created, the process has an open file handle that it uses for standard output. You would need to change that handle from *inside the process itself*. – chepner Apr 23 '14 at 19:59

1 Answers1

0

You can swap the file descriptors. Here's a quick script:

#!/bin/bash
#
# Swap/Roll a logfile
#
# Usage:              <old logfile>  <new logfile> [ optional pids ]
#         ./swap.sh /var/log/logfile /tmp/logfile  [pids]
#
# Author: Robert McKay <rob...@mckay.com>
# Date:   Tue Aug 14 13:36:35 BST 2007
#
# Update: Added usage message when needed, a fuser format fix,
#         some whitespace cleanup, and a localization fix.
#         Ingvar Hagelund <ingvar@redpill-linpro.com>
# Date:   Sat Jul 10 02:11:49 CEST 2010
# Update: Dereference symlinks provided as src or dst
#         Better quoting an escaping of variables
#         Cleanup and simplify
#         John Westlund <john...@westlund.us>
# Date:   Sat May 17 18:27:50 PDT 2014

if [ "$2" == "" ]; then
    echo "Usage: $0 /path/to/oldfile /path/to/newfile [pids]
Example: $0 /var/log/somedaemon.log /var/log/newvolume/somedaemon.log 1234
Example: $0 /dev/pts/53 /dev/null 1234
"
    exit 0
fi

if ! gdb --version > /dev/null 2>&1; then
    echo "Unable to find gdb."
    exit 1
fi

src="$(readlink -f "$1")"
dst="$(readlink -f "$2")"
shift; shift
pids="$@"

for pid in ${pids:=$( /sbin/fuser "$src" | cut -d ':' -f 2 )};
do
    echo "src=$src, dst=$dst"
    echo "$src has $pid using it"
    (
        echo "attach $pid"
        echo 'call open("'$dst'", 66, 0666)'
        pushd /proc/$pid/fd/ > /dev/null 2>&1
        LANG=C
        for ufd in *; do
                if [[ "$(readlink $ufd)" == "$src" ]]; then
                        echo 'call dup2($1,'"$ufd"')'
                fi
        done
        popd > /dev/null 2>&1
        echo 'call close($1)'
        echo 'detach'
        echo 'quit'
        sleep 5
    ) | gdb -q -x -
done

In your case you'll want to use the pts (stdout) that it's directed to currently.

# cat output.sh 
echo $$
while true; do date; sleep 1; done

# bash output.sh 
24468
Sun Apr 27 18:28:00 PDT 2014
Sun Apr 27 18:28:01 PDT 2014
Sun Apr 27 18:28:02 PDT 2014
^Z
[2]+  Stopped                 bash output.sh

# ls -l /proc/24468/fd/1 
lrwx------ 1 root root 64 Apr 27 18:28 /proc/24468/fd/1 -> /dev/pts/0

# /admin/scripts/swap_fds.sh /dev/pts/0 /tmp/test.out 24468
src=/dev/pts/0, dst=/tmp/test.out
/dev/pts/0 has 24468 using it
-: No such file or directory.
(gdb) Attaching to process 24468

Program received signal SIGTSTP, Stopped (user).
Reading symbols from /usr/bin/bash...Reading symbols from /usr/bin/bash...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Reading symbols from /lib64/libtinfo.so.5...Reading symbols from /lib64/libtinfo.so.5...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libtinfo.so.5
Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00000031614bb10a in waitpid () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install bash-4.2.45-1.fc18.x86_64
(gdb) $1 = 3
(gdb) $2 = 0
(gdb) $3 = 1
(gdb) $4 = 2
(gdb) $5 = 0
(gdb) Detaching from program: /usr/bin/bash, process 24468
warning: cannot close "/lib64/libtinfo.so.5": Invalid operation
(gdb) 18:28:43 XenMini /tmp 0
# bg
[2]+ bash output.sh &

# cat test.out
Sun Apr 27 18:29:49 PDT 2014
Sun Apr 27 18:29:50 PDT 2014

edit: Did a little more cleanup on the script

John Westlund
  • 336
  • 1
  • 10
  • Currently the script doesn't work on my system, but there's some output which I can't interpret as very unexperienced gdb user (and not post here due to length restriction). Maybe you have some ideas about requirements for my OS and in general (I'm running Ubuntu 14.04 amd64). Currently, I guess the most fatal error is `31 ../sysdeps/unix/sysv/linux/waitpid.c: No such file or directory.` – Kalle Richter Apr 28 '14 at 15:24
  • @KarlRichter That shouldn't be a fatal error. Make sure you've given the script the right PID. Are you seeing it switch the file descriptors? `$1 = 3 $2 = 0, etc` – John Westlund Apr 28 '14 at 17:43
  • Without root permissions (calling with sudo) I get `ptrace: operation not permitted`, with root permissions I'm getting `(gdb) $x = -1` for all file descriptors. – Kalle Richter Apr 28 '14 at 18:08