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 Ctrl+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
# Ctrl+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 how to redirect output is already answered in Redirect all output to file in Bash.

1
  • 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. Commented Apr 23, 2014 at 19:59

1 Answer 1

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 <[email protected]>
# 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 <[email protected]>
# 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 <[email protected]>
# 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

Sign up to request clarification or add additional context in comments.

3 Comments

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.
@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
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.