We collect practical, well-explained Bash one-liners, and promote best practices in Bash shell scripting. To get the latest Bash one-liners, follow @bashoneliners on Twitter. If you find any problems, report a bug on GitHub.



Format input into multiple columns, like a table, useful or pretty-printing

 $ mount | column -t

— by Janos on April 8, 2012, 4:08 p.m.


column is a utility for formatting text. With the -t flag it detects the number of columns in the input so it can format the text into a table-like format.

For more details see man column.


Function to extract columns from an input stream

 $ col() { awk '{print $'$(echo $* | sed -e 's/ /,$/g')'}'; }

— by Janos on April 5, 2012, 11:36 p.m.


Something I do a lot is extract columns from some input where cut is not suitable because the columns are separated by not a single character but multiple spaces or tabs. So I often do things like:

... | awk '{print $7, $8}'

... which is a lot of typing, additionally slowed down when typing symbols like '{}$ ... Using the simple one-line function above makes it easier and faster:

... | col 7 8

How it works:

  • The one-liner defines a new function with name col
  • The function will execute awk, and it expects standard input (coming from a pipe or input redirection)
  • The function arguments are processed with sed to use them with awk: replace all spaces with ,$ so that for example 1 2 3 becomes 1,$2,$3, which is inserted into the awk command to become the well formatted shell command: awk '{print $1,$2,$3}'


Resize an image proportionally to some specified width or height

 $ mogrify -geometry x31 path/to/image.gif

— by Janos on April 3, 2012, 9:48 p.m.


  • mogrify is part of ImageMagick, an image manipulation software suite
  • mogrify manipulates the specified images. If you prefer to keep the original image untouched and write the manipulated image to a different file, simply replace mogrify with convert, the syntax is the same, but the last command line argument will be the target image to write to.
  • The -geometry flag is to resize the image, it requires a dimension parameter in the format WIDTHxHEIGHT
  • The dimension in this example has no width, which means the image will be resized to height=31 pixels, and the width will be proportional.


ImageMagick is not a standard package, though it is open source and available in many systems.


Do something in another directory without going there

 $ (cd /path/to/somewhere; tar c .) > somewhere.tar

— by Janos on April 2, 2012, 10:24 p.m.


As explained superbly in man bash:

   (list) list is executed in a subshell environment (see  COMMAND  EXECU-
          TION  ENVIRONMENT below).  Variable assignments and builtin com-
          mands that affect the  shell's  environment  do  not  remain  in
          effect  after  the  command completes.  The return status is the
          exit status of list.

In other words, this is a handy way to do something somewhere else without having to go there and coming back.


Remove carriage return '\r' character in many files, without looping and intermediary files

 $ recode pc..l1 file1 file2 file3

— by Anon8MaLEqEp on March 31, 2012, 5:23 p.m.


The recode utility installed on many systems converts between character sets. This command is shorthand for recode IBM-PC..latin1 file1 file2 file3 which converts the given files from CRLF to LF line endings.


Find the target path a symlink is pointing to

 $ readlink a_symbolic_link_to_somewhere

— by Janos on March 31, 2012, 3:23 p.m.


Sure, you could figure out the link target from the output of ls -l a_symbolic_link_to_somewhere too, but the output of readlink is simply the target of the symbolic link itself, so it is cleaner and easier to read.


Get the octal, hexadecimal and decimal codes of the ASCII character set

 $ man ascii

— by Janos on March 29, 2012, 9:48 a.m.


Knowing the octal, hexadecimal or decimal code of the ASCII character set can be handy at times. In the past, too often I did things like:

perl -e 'for my $n (1 .. 255) { print $n, chr($n), $n, "\n"; }'

... when a simple man ascii would have done the trick...

On a related note, these all print the letter "A":

echo -e '\0101'
printf '\101'
printf '\x41'
perl -e 'print "\x41"'


List or edit and re-execute commands from the history list

 $ fc -l

— by Janos on March 15, 2012, 12:10 p.m.


fc is a little known but very useful bash built-in.

  • fc -l will list the most recent 16 commands
  • fc will open the last command in a text editor defined in the environmental variable FCEDIT or EDITOR or else vi, and re-execute when you exit
  • fc 5 9 will open the history entries 5 to 9 in a text editor
  • fc -s pat=sub will run the last command after substituting pat with sub in it (does not open editor)
  • fc -s pat=sub cc is the same but on the last command starting with cc
  • fc -s cc will run the last command starting with cc

For more info see help fc.


Find the most recently modified files in a directory and all subdirectories

 $ find /path/to/dir -type f -mtime -7 -print0 | xargs -0 ls -lt | head

— by Janos on March 8, 2012, 5:10 p.m.


  • find /path/to/dir -type f -mtime -7 -print0 prints all the files in the directory tree that have been modified within the last 7 days, with null character as the delimiter
  • xargs -0 ls -lt expects a null delimited list of filenames and will sort the files by modification time, in descending order from most recent to oldest
  • Since we are looking for the most recent files, with head we get the first 10 lines only

Note that if there are too many files in the output of find, xargs will run multiple ls -lt commands and the output will be incorrect. This is because the maximum command line length is getconf ARG_MAX and if this is exceeded xargs has to split the execution to multiple commands. So depending on your use case you may need to tweak the -mtime parameter to make sure there are not too many lines in the output.


List open files

 $ lsof -n

— by Janos on March 2, 2012, 10:01 a.m.


With the -n flag it will not try to resolve network numbers to host names for network files, making it run a bit faster.

With the -c option you can select processes executing a matching command. And with the -t flag the output will be simply process ids without a header, suitable to use with kill. For example you can kill Google Chrome process gone crazy like this:

kill -HUP $(lsof -n -c /google/i -t)

Here /google/i is a regular expression pattern with case insensitive matching.


Set a colorful bash prompt per dev test prod environments

 $ PS1='\[\e[1;31m\][\u@\h \W]\$\[\e[0m\] '

— by Janos on Feb. 25, 2012, 2:46 p.m.


It is useful to set a different color for the shell prompt in different deployment environments like dev/test/production, so that you don't mix up your multiple windows and do something by accident in the wrong window.

  • PS1 contains the format of the primary prompt
  • \[\e[1;31m\] sets the foreground color to red
  • \u will be substituted with the current username
  • \h will be substituted with the hostname
  • \W will be substituted with the current directory name
  • \[\e[0m\] is the end marker of the color setting

To make the color stand out even more for root users, the inverse color can be interesting too:

PS1='\[\e[7;31m\][\u@\h \W]\$\[\e[0m\] '

Other color examples:

#PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' # green
#PS1='\[\e[1;33m\][\u@\h \W]\$\[\e[0m\] ' # yellow
#PS1='\[\e[1;34m\][\u@\h \W]\$\[\e[0m\] ' # blue

You can learn more in man bash, search for "PROMPTING".


Your terminal program must support colors, of course ;-)


Calculate the total disk space used by a list of files or directories

 $ du -c

— by openiduser30 on Feb. 14, 2012, 1:34 a.m.


-c option of du prints the total size of the arguments


Print the lines of file2 that are missing in file1

 $ grep -vxFf file1 file2

— by Janos on Feb. 8, 2012, 2:42 p.m.


  • -f is to specify a file with the list of patterns: file1
  • -F is to treat the patterns fixed strings, without using regular expressions
  • -x is to match exactly the whole line
  • -v is to select non-matching lines

The result is effectively the same as:

diff file1 file2 | grep '^>' | sed -e s/..//


The flags of grep might work differently depending on the system. So yeah you might prefer the second way which should work everywhere. Nonetheless the various of flags of grep are interesting.


Find in files, recursively

 $ find /etc -type f -print0 2>/dev/null | xargs -0 grep --color=AUTO -Hn 'nameserver' 2>/dev/null

— by openiduser21 on Feb. 2, 2012, 7:32 p.m.


In the example above, find and display every file in /etc containing the string nameserver with the corresponding line, including line number, sample output:

/etc/ppp/ip-up.d/0dns-up:9:# Rev. Dec 22 1999 to put dynamic nameservers last.

/etc/ppp/ip-up.d/0dns-up:23:# nameservers given by the administrator. Those for which 'Dynamic' was chosen

/etc/ppp/ip-up.d/0dns-up:24:# are empty. 0dns-up fills in the nameservers when pppd gets them from the

/etc/ppp/ip-up.d/0dns-up:26:# 'search' or 'domain' directives or additional nameservers. Read the

/etc/ppp/ip-up.d/0dns-up:77:# nameserver lines to the temp file.


Concatenate PDF files using GhostScript

 $ gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=output.pdf -dBATCH file1.pdf file2.pdf file3.pdf

— by Janos on Jan. 26, 2012, 8:51 a.m.


Free PDF editing software might become more and more available, but this method has been working for a long time, and likely will continue to do so.


It may not work with all PDFs, for example files that don't conform to Adobe's published PDF specification.


Format text with long lines to text with fixed width

 $ fmt -s -w80 file.txt

— by Janos on Jan. 22, 2012, 10:08 a.m.


  • It will break lines longer than 80 characters at appropriate white spaces to make them less than 80 characters long.
  • The -s flag will collapse multiple consecutive white spaces into one, or at the end of a sentence a double space.


Come back quickly to the current directory after doing some temporary work somewhere else

 $ pushd /some/where/else; work; cd /somewhere; work; cd /another/place; popd

— by Janos on Jan. 15, 2012, 11:12 p.m.


  • pushd, popd and dirs are bash builtins, you can read about them with help dirs
  • bash keeps a stack of "remembered" directories, and this stack can be manipulated with the pushd and popd builtins, and displayed with the dirs builtin
  • pushd will put the current directory on top of the directory stack. So, if you need to change to a different directory temporarily and you know that eventually you will want to come back to where you are, it is better to change directory with pushd instead of cd. While working on the temporary task you can change directories with cd several times, and in the end when you want to come back to where you started from, you can simply do popd.


Export a git project to a directory

 $ git archive master | tar x -C /path/to/dir/to/export

— by Janos on Jan. 12, 2012, 11:04 a.m.


The git archive command basically creates a tar file. The one-liner is to create a directory instead, without an intermediate tar file. The tar command above will untar the output of git archive into the directory specified with the -C flag. The directory must exist before you run this command.


Delete all tables of a mysql database

 $ mysql --defaults-file=my.cnf -e 'show tables' | while read t; do mysql --defaults-file=my.cnt  -e 'drop table '$t; done

— by Janos on Jan. 8, 2012, 7:53 a.m.


If you have a root access to the database, a drop database + create database is easiest. This script is useful in situations where you don't have root access to the database.

First prepare a file my.cnf to store database credentials so you don't have to enter on the command line:






Make sure to protect this file with chmod go-rwx.

The one-liner will execute show tables on the database to list all tables. Then the while loop reads each table name line by line and executes a drop table command.


The above solution is lazy, because not all lines in the output of show tables are table names, so you will see errors when you run it. But hey, shell scripts are meant to be lazy!


Run remote X11 applications with ssh

 $ ssh -X servername

— by versorge on Jan. 5, 2012, 7:50 a.m.


You could follow this command with any other call to an X app: xeyes &


If ssh forwarding is permitted on the ssh server


Calculate the total disk space used by a list of files or directories

 $ du -s file1 dir1 | awk '{sum += $1} END {print sum}'

— by Janos on Dec. 28, 2011, 8:42 p.m.


  • This is really simple, the first column is the size of the file or the directory, which we sum up with awk and print the sum at the end.
  • Use du -sk to count in kilobytes, du -sm to count in megabytes (not available in some systems)


Check the performance of a script by re-running many times while measuring the running time

 $ for i in {1..10}; do time curl http://localhost:8000 >/dev/null; done 2>&1 | grep real

— by Janos on Dec. 17, 2011, 1:49 a.m.


  • {1..10} creates a sequence from 1 to 10, for running the main script 10 times
  • 2>&1 redirects stderr to stdout, this is necessary to capture the "output" of the time builtin


A convenient way to re-run the previous command with sudo

 $ sudo !!

— by Janos on Dec. 14, 2011, 11:26 p.m.


!! (bang bang!) is replaced with the previous command.

You can read more about it and other history expansion commands in man bash in the Event Designators section.


Put an ssh session in the background

 $ ~^z

— by Janos on Dec. 9, 2011, 7:44 p.m.


  • Normally, ^z (read: ctrl-z) pauses the execution of the current foreground task. That doesn't work in an ssh session, because it is intercepted by the remote shell. ~^z is a special escape character for this case, to pause the ssh session and drop you back to the local shell.
  • For all escape characters see ~?
  • The ~ escape character must always follow a newline to be interpreted as special.
  • See man ssh for more details, search for ESCAPE CHARACTERS


Recursively remove all empty sub-directories from a directory tree

 $ find . -type d | tac | xargs rmdir 2>/dev/null

— by Janos on Nov. 29, 2011, 8:01 p.m.


  • find will output all the directories
  • tac reverses the ordering of the lines, so "leaf" directories come first
  • The reordering is important, because rmdir removes only empty directories
  • We redirect error messages (about the non-empty directories) to /dev/null


In UNIX and BSD systems you might not have tac, you can try the less intuitive tail -r instead.