Detecting The Output Stream Type of a Shell Script

Detecting the output stream type of a shell script

See this previous SO question, which covers bash. Tcsh provides the same functionality with filetest -t 1 to see if standard output is a terminal. If it is, then print the color stuff, else leave it out. Here's tcsh:

#!/bin/tcsh
if ( -t 1 ) then
printf "\033[31m Success Color is awesome!\033[0m"
else
printf "Plain Text is awesome!"
endif

detect output stream on linux shell script

When stdout is not connected to a terminal, it's fully buffered by default. So if you want to be able to detect output immediately (as suggested by the sleep(1); in the code) you need to flush the buffer after printing.

#include "stdio.h"
void main(){
int i;
for (i=0; i<100; i++){
printf("data: %d\n", i);
fflush(stdout);
sleep(1); // delay 1s
}
}

Then you can pipe the output of the program to something in the script and it will detect the output without waiting for the program to finish.

How can I detect if my shell script is running through a pipe?

In a pure POSIX shell,

if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi

returns "terminal", because the output is sent to your terminal, whereas

(if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi) | cat

returns "not a terminal", because the output of the parenthetic element is piped to cat.


The -t flag is described in man pages as

-t fd True if file descriptor fd is open and refers to a terminal.

... where fd can be one of the usual file descriptor assignments:

  • 0: standard input
  • 1: standard output
  • 2: standard error

Detect in C if outputting to a terminal

Use isatty():

$ man isatty
ISATTY(3) Linux Programmer's Manual ISATTY(3)

NAME
isatty - does this descriptor refer to a terminal

SYNOPSIS
#include <unistd.h>

int isatty(int desc);

DESCRIPTION
returns 1 if desc is an open file descriptor connected to a terminal
and 0 otherwise.

Since stdout is always file descriptor 1, you can do:

if(isatty(1))
// stdout is a terminal

Checking if output of a command contains a certain string in a shell script

Test the return value of grep:

./somecommand | grep 'string' &> /dev/null
if [ $? == 0 ]; then
echo "matched"
fi

which is done idiomatically like so:

if ./somecommand | grep -q 'string'; then
echo "matched"
fi

and also:

./somecommand | grep -q 'string' && echo 'matched'

how to check for output of a program in bash scripting?

It's possible, but you normally don't.

You can pick the exit code of the last command, 0 is 0 Errors, every other value indicates some kind of error, application specific or just a general error. With $? you get the exit code from the last command, but you have to use it immediately after the command in question.

((3 < 1)) ; err=$?; echo $err
1
((3 > 1)) ; err=$?; echo $err
0

Error messages often depend on LOCALE settings:

erg=$(LC_ALL=C ls nosuchsamplefile 2>&1)
echo "$erg"
ls: cannot access 'nosuchsamplefile': No such file or directory

erg=$(ls nosuchsamplefile 2>&1)
echo $erg
ls: Zugriff auf 'nosuchsamplefile' nicht möglich: Datei oder Verzeichnis nicht gefunden

Comparing words can fail and is inherently insecure. Even by setting the command to a specific setting can't prevent updates from changing the wording and surely, the user had set his Locale to some different value for a reason.

However, 2 > &1 redirects the error stream to the output, which is the default for the screen, but on capturing, it makes a difference. As long as you just script for yourself and in ad hoc situations, approaches can be useful, which don't scale with multiple users and when to be maintained over years.

write to output stream and returning value from shell script function

Would this work?:

#this is a function that returns a value, as well as                            
#print some messages
function logic(){
echo "start of logic"
echo "perform logic, to get value"

echo "ok" >&2
}

function smain(){
{ local result=$( { { logic ; } 1>&3 ; } 2>&1); } 3>&1

echo "result is >$result<"

if [ "$result" == "ok" ];then
echo "script successful"
else
echo "script failed"
fi
}

smain

Check if user has typed something while script is running

You can use the read command with the timeout option read -t. For example the below script detects the string 'cc'. You can also specify the number of characters to read with -N so that user does not have to press enter.

flag=0
while true; do
sleep 3
if [[ $flag -eq 0 ]];then
echo user
else
echo sys
fi
read -t 0.25 -N 2 input
if [[ $input = "cc" ]] ; then
[[ $flag -eq 0 ]] && flag=1 || flag=0
fi
done

Test if a command outputs an empty string

Previously, the question asked how to check whether there are files in a directory. The following code achieves that, but see rsp's answer for a better solution.


Empty output

Commands don’t return values – they output them. You can capture this output by using command substitution; e.g. $(ls -A). You can test for a non-empty string in Bash like this:

if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi

Note that I've used -A rather than -a, since it omits the symbolic current (.) and parent (..) directory entries.

Note: As pointed out in the comments, command substitution doesn't capture trailing newlines. Therefore, if the command outputs only newlines, the substitution will capture nothing and the test will return false. While very unlikely, this is possible in the above example, since a single newline is a valid filename! More information in this answer.


Exit code

If you want to check that the command completed successfully, you can inspect $?, which contains the exit code of the last command (zero for success, non-zero for failure). For example:

files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi

More info here.



Related Topics



Leave a reply



Submit