piping output from programs that do not output to STDOUT - bash

Say I have a program that outputs to a file which is provided by an (required) argument:
./foo -o bar.txt
Is there any way to trick it into outputting to a pipe? This just outputs to a file named -.
./foo -o - | less

You can use /dev/stdout as the file name:
./foo -o /dev/stdout | less

This will feed the contents of bar.txt to filter as the file grows:
tail -f bar.txt | filter

other solution, create a named pipe:
mkfifo /tmp/myfifo; ./foo -o /tmp/myfifo
</tmp/myfifo cat -

Related

Testing whether stdin is a file vs. a pipe vs. a tty

I know for bash and zsh, one can use e.g. [ -t 1 ] to determine if STDIN is an interactive tty session.
However, there doesn't seem to be a way to test whether stdin is being redirected from a file, versus being piped in from a command:
foo < ./file
bar | foo
Is there any way to detect the difference between these two? Separately, is there any way to get the path of the file being redirected from (outside of /proc/self, which is unavailable on macOS)?
You can check if /dev/stdin is a regular file or a pipe:
$ cat tmp.sh
#!/bin/bash
if [ -f /dev/stdin ]; then
echo "file"
elif [ -p /dev/stdin ]; then
echo "pipe"
fi
$ bash tmp.sh < foo.txt
file
$ echo foo | bash tmp.sh
pipe
This relies on /dev/stdin being in your file system, though.
You can also use the stat command, which will return information about standard input given no file name argument. As you mentioned you are using macOS, you can use the %HT format:
$ stat -f %HT
Character Device
$ stat -f %HT < foo.txt
Regular File
$ echo foo | stat -f %HT
Fifo File

Piping and redirecting with cat

Looking over the Dokku source code, I noticed two uses of pipe and redirect that I am not familiar with.
One is: cat | command
Example: id=$(cat | docker run -i -a stdin progrium/buildstep /bin/bash -c "mkdir -p /app && tar -xC /app")
The other is cat > file
Example: id=$(cat "$HOME/$APP/ENV" | docker run -i -a stdin $IMAGE /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/app-env.sh")
What is the use of pipe and redirect in the two cases?
Normally, both usages are completely useless.
cat without arguments reads from stdin, and writes to stdout.
cat | command is equivalent with command.
&& cat >file is equivalent with >file, assuming the previous command processed the stdin input.
Looking at it more closely, the sole purpose of that cat command in the second example is to read from stdin. Without it, you would redirect the output of mkdir to the file. So the command first makes sure the directory exists, then writes to the file whatever you feed to it through the stdin.

redirect stdin and stdout using tee and keep previous std

How can I both write to a file and display to screen using pipe with tee?
This command actually do it, the problem is that it writes to a new file and tail -f give me an error "truncate file".
ls -al | tee file.txt
-a option of tee is what you are looking for
-a, --append
append to the given FILEs, do not overwrite
so your line would be:
ls -al | tee -a file.txt

Supress grep output but capture it in a variable

I'm trying to get the following line to work
WERRORS=`echo $VALPG | grep -q -s -o -m 1 '\<[0-9]* Errors'`
What I want is that the result of grep go into WERRORS variable but not echo in the terminal.
So i use -q, but then WERRORS is empty
If grep sends any error messages, they go to the error output, which is not captured by the backticks. If you need this output in a variable (which is somewhat problematic, because it's often localized), redirect it using 2>&1:
WERRORS=`echo $VALPG | grep -s -o -m 1 '\<[0-9]* Errors' 2>&1`
WERRORS=`echo $VALPG | grep -s -o -m 1 '\<[0-9]* Errors'`
kent$ val=abcpc
kent$ a=$(echo $val|grep -o -m 1 -s 'pc')
kent$ echo $a
pc

bash output redirect prob

I want to count the number of lines output from a command in a bash script. i.e.
COUNT=ls | wc -l
But I also want the script to output the original output from ls. How to get this done? (My actual command is not ls and it has side effects. So I can't run it twice.)
The tee(1) utility may be helpful:
$ ls | tee /dev/tty | wc -l
CHANGES
qpi.doc
qpi.lib
qpi.s
4
info coreutils "tee invocation" includes this following example, which might be more instructive of tee(1)'s power:
wget -O - http://example.com/dvd.iso \
| tee >(sha1sum > dvd.sha1) \
>(md5sum > dvd.md5) \
> dvd.iso
That downloads the file once, sends output through two child processes (as started via bash(1) process substitution) and also tee(1)'s stdout, which is redirected to a file.
ls | tee tmpfile | first command
cat tmpfile | second command
Tee is a good way to do that, but you can make something simpler:
ls > __tmpfile
cat __tmpfile | wc -l
cat __tmpfile
rm __tmpfile

Resources