This is a short list of useful intermediate bash tricks. Often, the problem with this kind of posts in my opinion is that some tricks are explained, but it is not made clear when to use them. Thus, I try to introduce these techniques using a problem. I will discuss command substitution, process substitution and the heredoc syntax.

Command Substitution


Say, I want to find out which libraries the command cat uses. Determining the libraries can be done using the command ldd. However, ldd takes a file as an argument. Consequently I have to find out where cat is and then invoke ldd on it.

hk@localhost:~$ which cat
hk@localhost:~$ ldd /usr/bin/cat (0x00007fff944f0000) => /lib64/ (0x00007fe7d6b11000)
	/lib64/ (0x00007fe7d70da000)

That is far too much to type.


Bash can substitute a command by its result if it is between backticks. A more modern approach is writing the command $(like this). As we do not care where cat lives, we can use the following code.

hk@localhost:~$ ldd $(which cat) (0x00007ffd8e9e8000) => /lib64/ (0x00007f6975f48000)
	/lib64/ (0x00007f6976511000)

In general, Bash substitutes the string $(command) by the result of invoking command.

Process Substitution


The same can be done using processes. Say, we want to base64 encode the string “Hallo”. Further, we do not know that base64 can read from standard input when given - as filename. Consequently, as base64 reads from a file, we would have to write “Hallo” to a file and then base64 encode it.

hk@localhost:~$ echo "Hallo" > temp
hk@localhost:~$ base64 temp
hk@localhost:~$ rm temp

Argh! What a waste. Why can’t we use a temporary file which deletes itself?


Well, it turns out we can. With the syntax <(command) bash gives us a temporary file which contains the result of running command. Thus, we can do the following:

hk@localhost:~$ base64 <(echo "Hallo")

What happens here is that Bash generates a temporary file descriptor.

hk@localhost:~$ echo <(echo "Hallo")

This is a symbolic link to a pipe.

hk@localhost:~$ file <(echo "Hallo")
/dev/fd/63: broken symbolic link to pipe:[3115050]

Don’t ask me why it says that it is broken. Perhaps due to some race condition.



You are on a server and do not have a nice text editor. Say, you are in a reverse shell. Nevertheless, you have a multi-line kernel exploit which you want to use.


hk@localhost:~$ cat > file.txt <<EOF
> first line
> second line
> third line

This reads up to the string EOF, and puts that stuff into file.txt.

hk@localhost:~$ cat file.txt
first line
second line
third line


29 September 2019


Computer Trick