Messing around with stdin, stdout, and stderr
Well, if we tinker a little bit with the file descriptors and special characters we can have some nice, really nice, outcomes; let's see what we can do.
x < filename
: This opens a file in read mode and the descriptor nameda
, whose value falls between3
and9
. We can choose any name by the means of which we can easily access the file content through thestdin
.1 > filename
: This redirects the standard output to filename. If it does exist, it gets created; if it exists, the pre-existing data is overwritten.1 >> filename
: This redirects the standard output to filename. If it does exist, it is created; otherwise, the contents get appended to the pre-existing data.2 > filename
: This redirects the standard error to filename. If it does not exist, it gets created; if it exists, the pre-existing data is overwritten.2 >> filename
: This redirects the standard error to filename. If it does not exist, it is created; otherwise, the contents get appended to the pre-existing data.&> filename
: This redirects both thestdout
and thestderr
to filename. This redirects the standard error to filename. If it does not exist, it gets created; if it exists, the pre-existing data is overwritten.2>&1
: This redirects thestderr
to thestdout
. If you use this with a program, its error messages will be redirected to thestdout
, that is, usually, the monitor.y>&x
: This redirects the file descriptor fory
tox
so that the output from the file pointed by descriptory
will be redirected to the file pointed by descriptorx
.>&x
: This redirects the file descriptor1
that is associated with thestdout
to the file pointed by the descriptorx
, so whatever hits the standard output will be written in the file pointed byx
.x<> filename
: This opens a file in read/write mode and assigns the descriptorx
to it. If the file does not exist, it is created, and if the descriptor is omitted, it defaults to0
, thestdin
.x<&-
: This closes the file opened in read mode and associated with the descriptorx
.0<&- or <&-
: This closes the file opened in read mode and associated with the descriptor0
, thestdin
, which is then closed.x>&-
: This closes the file opened in write mode and associated with the descriptorx
.1>&- or >&-
: This closes the file opened in write mode and associated with the descriptor1
, thestdout
, which is then closed.
If you want to see which file descriptors are associated with a process, you can explore the /proc
directory and point to the following:
/proc/pid/fd
Under that path, change PID
with the ID of the process you want to explore; you will find all the file descriptors associated with it, as in the following example:
gzarrelli:~$ ls -lah /proc/15820/fd total 0 dr-x------ 2 postgres postgres 0 Jan 20 17:59 . dr-xr-xr-x 9 postgres postgres 0 Jan 20 09:59 .. lr-x------ 1 postgres postgres 64 Jan 20 17:59 0 -> /dev/null (deleted) l-wx------ 1 postgres postgres 64 Jan 20 17:59 1 -> /var/log/postgresql/postgresql-9.4-main.log lrwx------ 1 postgres postgres 64 Jan 20 17:59 10 -> /var/lib/postgresql/9.4/main/base/16385/16587 lrwx------ 1 postgres postgres 64 Jan 20 17:59 11 -> socket:[13135] lrwx------ 1 postgres postgres 64 Jan 20 17:59 12 -> socket:[1502010] lrwx------ 1 postgres postgres 64 Jan 20 17:59 13 -> /var/lib/postgresql/9.4/main/base/16385/16591 lrwx------ 1 postgres postgres 64 Jan 20 17:59 14 -> /var/lib/postgresql/9.4/main/base/16385/16593 lrwx------ 1 postgres postgres 64 Jan 20 17:59 15 -> /var/lib/postgresql/9.4/main/base/16385/16634 lrwx------ 1 postgres postgres 64 Jan 20 17:59 16 -> /var/lib/postgresql/9.4/main/base/16385/16399 lrwx------ 1 postgres postgres 64 Jan 20 17:59 17 -> /var/lib/postgresql/9.4/main/base/16385/16406 lrwx------ 1 postgres postgres 64 Jan 20 17:59 18 -> /var/lib/postgresql/9.4/main/base/16385/16408 l-wx------ 1 postgres postgres 64 Jan 20 17:59 2 -> /var/log/postgresql/postgresql-9.4-main.log lr-x------ 1 postgres postgres 64 Jan 20 17:59 3 -> /dev/urandom l-wx------ 1 postgres postgres 64 Jan 20 17:59 4 -> /dev/null (deleted) l-wx------ 1 postgres postgres 64 Jan 20 17:59 5 -> /dev/null (deleted) lr-x------ 1 postgres postgres 64 Jan 20 17:59 6 -> pipe:[1502013] l-wx------ 1 postgres postgres 64 Jan 20 17:59 7 -> pipe:[1502013] lrwx------ 1 postgres postgres 64 Jan 20 17:59 8 -> /var/lib/postgresql/9.4/main/base/16385/11943 lr-x------ 1 postgres postgres 64 Jan 20 17:59 9 -> pipe:[13125]
Nice, isn't it? So, let us do something that is absolute fun:
First, let's open a socket in read/write mode to the web server of a virtual machine created for this book and assign the descriptor 9
:
gzarrelli:~$ exec 9<> /dev/tcp/172.16.210.128/80 || exit 1
Then, let us write something to it; nothing complex:
gzarrelli:~$ printf 'GET /index2.html HTTP/1.1\nHost: 172.16.210.128\nConnection: close\n\n' >&9
We just requested a simple HTML file created for this example.
And now let us read the file descriptor 9
:
gzarrelli:~$ cat <&9 HTTP/1.1 200 OK Date: Sat, 21 Jan 2017 17:57:33 GMT Server: Apache/2.4.10 (Debian) Last-Modified: Sat, 21 Jan 2017 17:57:12 GMT ETag: "f3-5469e7ef9e35f" Accept-Ranges: bytes Content-Length: 243 Vary: Accept-Encoding Connection: close Content-Type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <HTML> <HEAD> <TITLE>This is a test file</TITLE> </HEAD> <BODY> <P>And we grabbed it through our descriptor! </BODY> </HTML>
That's it! We connected the descriptor to a server through a socket, we could write to it and read the response, redirecting the streams over the network.
For dealing just with the command line, we have done a so far, but if we want to go further, we have to see how to script all these commands and make the most out of them. It is time for our first script!