2

From within a shell script (sh/bash), how can I tell what device or file name I am redirecting to?

For example, I have a shell script named script.sh.

I run the shell script and redirect STDOUT to a file named out.txt, and redirect STDERR to a file named err.txt.

So, that would look like this:

$ ./script.sh > out.txt 2> err.txt

Now, from within the shell script, I can tell if STDOUT (or STDERR) is being redirected, or not:

if [ -t 1 ]; then...
if [ ! -t 1 ]; then...

but, once I know STDOUT (or STDERR) is being redirected, how can I tell where it is being rdirected to?

6
  • Why would the script need to care? Feb 9, 2014 at 5:04
  • @IgnacioVazquez-Abrams - The script will run for hours and will generate many Gigabytes of output. I want to (every so often) check the size of the redirect file and restart the script with redirection to a different file if (when) it gets larger than some size (the script is written so that it can be stopped and restarted, and it will resume where it was before it was stopped). Feb 9, 2014 at 5:23
  • 1
    That's something the external script should be handling. The one that knows where it's redirecting to. Feb 9, 2014 at 5:23
  • @IgnacioVazquez-Abrams - The script is being started from the command line. I could write a "wrapper" script to start the main script, and the "wrapper" would know the name of the redirect file, but once the "wrapper" calls the main script, the "wrapper" waits (does nothing) until the main script completes and exits... by then, it would be meaningless for the "wrapper" script to check the redirect file anymore. Feb 9, 2014 at 5:35
  • @IgnacioVazquez-Abrams - If the answer to my question is that "it can't be done", then I can find workarounds involving various ways of passing the name of the redirect file to the main script, or starting the mainscript in the background, and let the "wrapper" monitor the redirect file. But all this adds levels of unnecessary complexity if what I'm asking can be done. Feb 9, 2014 at 5:40

2 Answers 2

3

You could use lsof:

/usr/sbin/lsof -p $$ -a -d 1

The above would list just file descriptor 1 for just the current process:

COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash    5054 matt    1u   CHR  136,1      0t0    4 /dev/pts/1
3
  • Thank you. THis is probably what I wanted. But, unfortunately, lsof is not found on my machine. Here is my output of uname: Linux 3.2.52 #9 SMP Tue Oct 29 11:08:09 CDT 2013 x86_64 GNU/Linux Feb 9, 2014 at 12:50
  • It's found in /usr/sbin rather than /usr/bin, so if sbin isn't the the PATH for your script that's the problem. If it's not in sbin either, then use your distribution's package manager to get the lsof package. Feb 9, 2014 at 17:48
  • 1
    Eureka! I found it in /usr/sbin. It seems to be working. I ran it as "/usr/sbin/lsof -p $$ -a -d 1", and it came back with hundreds of warnings like: "lsof: WARNING: can't stat() ext4 file system /home/...folder". So, I added the "-w" switch. And, in order to only get the file-size and filename, I also added "-Fsn". Running "/usr/sbin/lsof -p$$ -a -d 1 -w -Fsn" produced: "p1234 \n s288355 \n n/home/...path/filename". So, I needed to use grep and sed to remove the "p1234" (PID) line, and the leading "s" and "n" before the file-size and filename. Feb 10, 2014 at 22:23
1

You generally do things such as "watch" scripts, by watching them from the either the outside or from the script that called this subordinate script.

$ ./script.sh > out.txt 2> err.txt &
[1] 6280

Now we watch:

$ watch "ls -l out.txt err.txt"
Every 2.0s: ls -l out.txt err.txt                        Sun Feb  9 00:30:37 2014

-rw-rw-r--. 1 saml saml 0 Feb  9 00:30 err.txt
-rw-rw-r--. 1 saml saml 0 Feb  9 00:30 out.txt

Every 2 seconds (you can change this) the output will get updated:

Every 2.0s: ls -l out.txt err.txt                        Sun Feb  9 00:30:39 2014

-rw-rw-r--. 1 saml saml 200 Feb  9 00:30 err.txt
-rw-rw-r--. 1 saml saml 200 Feb  9 00:30 out.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .