Have you ever started a long running command and then wanted to put it in the background but it's sending its output to STDOUT ? Here's a script that uses gdb to swap a processes file descriptors so you can send all that output to a file, or /dev/null after the fact. It may not be the most elegant solution, so any suggestions on ways to improve it are welcome!

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

You can use it like this:

# 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) # bg [2]+ bash output.sh & # cat test.out Sun Apr 27 18:29:49 PDT 2014 Sun Apr 27 18:29:50 PDT 2014