Search code examples
shellexecposixio-redirection

Confused about exec redirection to /dev/null, am I doing it correctly?


Background

I am training myself in POSIX shell scripting, please avoid any Bashism while answering. Thank you.

I know now, thanks to Kusalananda's answer, how to determine if my script is running interactively, i.e. when it is connected to stdin.


Question

As I rarely use exec (man page), I am unsure if I am doing the following idea correctly? Please elaborate.

If the script is running:

  • interactively: Output error messages into stderr, otherwise run in the default environment settings.

  • non-interactively: Redirect all output to /dev/null in this example (in the end I will likely want to redirect stdout and stderr to actual files).


Code

# test if file descriptor 0 = standard input is connected to the terminal
running_interactively () { [ -t 0 ]; }

# if not running interactively, then redirect all output from this script to the black hole
! running_interactively && exec > /dev/null 2>&1

print_error_and_exit ()
{
    # if running interactively, then redirect all output from this function to standard error stream
    running_interactively && exec >&2

    ...
}

Solution

  • It seems I was close. Since the running_interactively function worked as expected, I was able to move on with redirecting to files as follows.

    I have edited this answer to have more code for re-use.


    #!/bin/sh
    
    is_running_interactively ()
    # test if file descriptor 0 = standard input is connected to the terminal
    {
        # test if stdin is connected
        [ -t 0 ]
    }
    
    redirect_output_to_files ()
    # redirect stdout and stderr
    # - from this script as a whole
    # - to the specified files;
    #   these are located in the script's directory
    {
        # get the path to the script
        script_dir=$( dirname "${0}" )
    
        # redirect stdout and stderr to separate files
        exec >> "${script_dir}"/stdout \
            2>> "${script_dir}"/stderr
    }
    
    is_running_interactively ||
    # if not running interactively, add a new line along with a date timestamp
    # before any other output as we are adding the output to both logs
    {
        redirect_output_to_files
        printf '\n'; printf '\n' >&2
        date; date >&2
    }
    
    print_error_and_exit ()
    {
        # if running interactively redirect all output from this function to stderr
        is_running_interactively && exec >&2
        ...
    }