input output, file, pipe, redirections and parameters
Fuck this cryptic syntax.
§ Redirection
example
#! /usr/bin/bash
echo_to_err() { printf "%s\n" "$*" >&2; }
echo "msg to stdout"
echo_to_err "msg to stderr"
console output is not standard output
Typically, your shell would print both program stdout
and stderr
.
If you run ./example > hello.txt
,
the hello.txt
would only contain msg to stdout
and your console would only show
msg to stderr
shut the fuck up
Redirect everything to black hole. note that you need to redirect stdout
to
file first, then redirect stderr
to stdout
[^order]
$ ./example > /dev/null 2>&1
ordering of redirect
in the last example you need to first redirect stdout
to file then stderr
to
stdout
. this post
nicely explain why the ordering is like this.
In a nutshell: >
is an asignment, not an arrow! e.g. with > file
you asign
file (rvalue) to 1
(lvalue), NOT point 1 to file.
> /dev/null # 1 becomes `file`
2>&1 # 2 becomes value of 1 i.e. `file`
# & is like $, marking a variable)
symbols
< input redirection
<< input redirection, here document
<<< input redirection, here string
> output redirect, overwrite if targeting file
>> output redirect, append if targeting file
redirect flle to program stdin:
wc < file
duplicate the stream
command | tee <file>
:
Keep tty output and write to file (i.e. , do not redirect). In the following
example both msg to stdout
and msg to stderr
are printed to tty;
but only msg to stdout
is written to log.txt
$ ./example | tee log.txt
redirect stderr to stdout
use 2>&1
$ ./example 2>&1 | tee log.txt
file descriptors:
0 for stdout
, 1 for stdin
, 2 for stderr
char devices
/dev/null
- black hole, swallows whatever you give it without side effect. Useful for silencing program output. Unlike this provides no output if you read it.
/dev/zero
- continuous stream of NULL, can be used to wipe a storage device with
dd
(if you know what you are doing…) /proc/<PID>/fd/
- file descriptors of process
<PID>
for normally both0
and1
are linked to/dev/tty*
but redirecting things to these FDs may not work as you expected…. /dev/stdin -> /proc/self/fd/0
/dev/stdout -> /proc/self/fd/1
/dev/stderr -> /proc/self/fd/2
- duplicated fds for the current process’s stdio
here string
$ COMMAND <<< $THING
Is (effectively) equivalent to
echo $THING | COMMAND
Where $THING
is expanded and fed to stdin of COMMAND. However the later
echo-pipe example essentially creates two processes (echo and COMMAND) and
redirect one’s stdout
to another’s stdin
.
here document
$ COMMAND << EOF
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec,
pellentesque eu,
EOF
Example. print here documnet to a file
cat << EOF >> output.tex
this
is
a
test
EOF
§ Pipe & Socket & term // TODO
// TODO //
§ Parameters
NOTE: this one is not about bash scripting, i.e. I won’t include stuffs like “how can I parse commandline options”
double minus --
marks the end of command options. After which only positional arguments are
accecpted. For example if you have a file called -v
, cat -v
won’t work
because -v
is treated as an argument to cat
. Instead do cat -- -v
single minus -
It depends of commands. But most intriguingly: use with a pipe, to use a
program’s output as another’s parameter.
$ echo "hello" | rm -
equals
$ rm hello
or
$ rm $(echo "hello")
Another useful example is
$ pacman -Qtdq | sudo pacman -Rns -
which finds and kill the orphans (evil pun
intended)
§ Privilege
redirects are performed by the shell. Sudo gives privelege to the annoted program, not to the shell. e.g. the following won’t work even with sudo
$ sudo echo 0 > /proc/sys/kernel/sysrq
warning: An error occurred while redirecting file '/proc/sys/kernel/sysrq'
open: Permission denied
wordaround with tee:
$ echo 0 | sudo tee /proc/sys/kernel/sysrq
§ Parallelization?
Just an example how you may make things faster with a redirect.
Say you have a program like this: you produce a high throughput of data,
compress it (via gzip/zlib stream) and store it to disk.
Say, the get_data()
is more busy than the zlib compression.
Instead of
my_program > output.gz
You could use a simple uncomressed stream in the program and do the compression externally.
mkfifo temp.pipe
myprogram > temp.pipe && \
gzip -cf1 <temp.pipe >output.gz
For cache utilization, your system scheduler may heuristically run
myprogram
and gzip
on the same CPU. To force affinity:
taskset -c 0 myprogram > temp.pipe & \
taskset -c 1 gzip -cf1 < output.gz
But it really depends on your data throughput vs computation leverage. Sharing data between CPUs comes with a cost (you would certainly hit L3). The above example may give you little to no gain.
§ what do you mean “foreground” and “background”
refs
- here string: https://tldp.org/LDP/abs/html/x17837.html
- more on how here string works vs. pipe: https://unix.stackexchange.com/a/219805
- bash redirections, GNU: https://www.gnu.org/software/bash/manual/html_node/Redirections.html