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.

Tags

0

Rename all files in a directory to upper case

 $ for i in *; do mv "$i" "${i^^}"; done

— by EvaggelosBalaskas on April 20, 2013, 9:53 p.m.

Explanation

Loop over the items in the current directory, and use Bash built-in case modification expansion to convert to upper case.

Limitations

The case modification extension is available since Bash 4.

0

Print file owners and permissions of a directory tree

 $ find /path/to/dir1 -printf "%U %G %m %p\n" > /tmp/dir1.txt

— by Janos on March 19, 2013, 10:51 p.m.

Explanation

The command simply traverses the specified directory tree and for each file and directory it prints the UID of the owner, GID of the group, the permission bits and the path.

To compare file owners and permissions of two directory trees you can run this command for each directory, save the output in two files and then compare them using diff or similar.

See man find for more explanation of all the possible symbols you can use with -printf

Limitations

The -printf option does not exist in find on Solaris 10.

0

Get only the latest version of a file from across mutiple directories

 $ find . -name custlist\* | perl -ne '$path = $_; s?.*/??; $name = $_; $map{$name} = $path; ++$c; END { print $map{(sort(keys(%map)))[$c-1]} }'

— by Janos on Feb. 23, 2013, 4:23 p.m.

Explanation

The purpose of the one-liner is to find the the "latest" version of the custlist_*.xls file from among multiple versions in directories and sub-directories, for example:

./c/custlist_v1.003.xls
./c/custlist_v2.001.xls
./d/b/custlist_v1.001.xls
./d/custlist_v1.002.xls

Let's decompose the one-liner to the big steps:

  • find . -name custlist\* -- find the files matching the target pattern
  • ... | perl -ne '...' -- run perl, with the input wrapped around in a while loop so that each line in the input is set in the variable $_
  • $path = $_; s?.*/??; $name = $_; -- save the full path in $path, and cut off the subdirectory part to get to the base name of the file and save it in $name
  • $map{$name} = $path; -- build a mapping of $name to $path
  • ++$c; -- we count the elements, to use it later
  • (sort(keys(%map)))[$c-1] -- sort the keys of the map, and get the last element, which is custlist_v2.001.xls in this example
  • END { print $map{$last} }' -- at the end of all input data, print the path of the latest version of the file

Limitations

Even if the latest version of the file appears multiple times in the directories, the one-liner will print only one of the paths. This could be fixed though if needed.

0

Recreate or update an existing zip file and remove files that do not exist anymore

 $ zip --filesync -r /path/to/out.zip /path/to/dir

— by Janos on Jan. 26, 2013, 8:48 p.m.

Explanation

zip does not have an explicit option to overwrite/recreate an existing zip file. If the specified destination file already exists, zip updates it. The problem is that files you did not specify to add to the zip but they already existed in the zip, will not be removed.

For example let's say you created a zip file from a directory with the command:

zip -r /path/to/out.zip /path/to/dir

Next you delete some files from the directory and repeat the command to recreate the zip. But that will not recreate the zip, it will only update it, and so the file you deleted from the directory will still be there in the zip.

One way to recreate the zip is to delete the file first. Another, better way is to use the --filesync or -FS flag. With this flag zip will remove files from the zip that do not exist anymore in the filesystem. This is more efficient than recreating the zip.

0

How to expand a CIDR notation to its IPs

 $ for j in $(seq 0 255); do for i in $(seq 0 255) ; do seq -f "10.$j.$i.%g" 0 255; done; done

— by EvaggelosBalaskas on Jan. 16, 2013, 11:53 a.m.

Explanation

Using two for loops to create second & third block of IP and finally through a formatted seq to printf the output.

More efficient/using less memory than using {..} (range).

Limitations

seq is not available by default in some systems.

0

Make the output of the `time` builtin easier to parse

 $ TIMEFORMAT=%R

— by Janos on Dec. 4, 2012, 10:43 p.m.

Explanation

The time builtin prints a summary of the real time, user CPU time and system CPU time spent executing commands, for example:

$ time sleep 1

real    0m1.002s
user    0m0.000s
sys     0m0.002s

If you need to parse this output, it helps to simplify it using the TIMEFORMAT variable. The value %R means "the elapsed time in seconds", for example:

$ TIMEFORMAT=%R
$ time sleep 1
1.004

The complete documentation of the format definition is in man bash, search for TIMEFORMAT.

0

Remove EXIF data such as orientation from images

 $ mogrify -strip /path/to/image.jpg

— by Janos on Oct. 24, 2012, 12:08 a.m.

Explanation

I use this mostly to remove orientation information from images. My problem with orientation information is that some viewers don't support it, and thus do not show the image correctly oriented. Rotating the image doesn't help, because if I make the image look correct in the viewer that doesn't support orientation, that will break it in the viewer that does support orientation. The solution is to remove the orientation information and rotate the image appropriately. That way the image will always look the same in all viewers, regardless of support for the orientation information.

The tool mogrify is part of ImageMagick, an image manipulation software. It manipulates image files and saves the result in the same file. A similar tool in ImageMagick that saves the result of manipulations is convert, you can use it like this:

convert -strip orig.jpg stripped.jpg

Limitations

The tool is part of ImageMagick, an image manipulation software.

0

Get the last modification date of a file in any format you want

 $ date -r /etc/motd +%Y%m%d_%H%M%S

— by Janos on Oct. 17, 2012, 4:42 p.m.

Explanation

The -r flag is a shortcut of --reference and it is used to specify a reference file. Used in this way, the date command prints the last modification date of the specified file, instead of the current date.

The + controls the output format, for example:

  • %Y = 4-digit year
  • %m = 2-digit month
  • %d = 2-digit day
  • %H = 2-digit hour
  • %M = 2-digit minutes
  • %S = 2-digit seconds

So in this example +%Y%m%d_%H%M%S becomes 20121001_171233

You should be able to find all the possible format specifiers in man date.

Limitations

The default date command in Solaris does not support the --reference flag. Modern Solaris systems have the GNU tools installed, so you may be able to find the GNU implementation of date which supports this flag. Look for it in /usr/gnu/bin/date or /usr/local/bin/date, or do search the entire /usr with find /usr -name date.

In Solaris this may be a suitable substitute without using the date command:

ls -Ego /etc/motd | awk '{print $4 "_" $5}' | tr -d :- | sed -e 's/\..*//'

Or you can use good old perl:

perl -mPOSIX -e 'print POSIX::strftime("%Y%m%d_%H%M%S\n", localtime((stat("/etc/motd"))[9]))'

0

Forget all remembered path locations

 $ hash -r

— by Janos on Oct. 14, 2012, 9:46 a.m.

Explanation

bash remembers the full path name of each command you enter, so it doesn't have to lookup in $PATH every single time you run the same thing. It also counts the number of times you used each command in the current session, you can see the list with hash.

Anyway, this behavior can poses a small problem when you reinstall an application at a different path. For example you reinstall a program that used to be in /usr/local/bin and now it is in /opt/local/bin. The problem is that if you used that command in the current shell session, then bash will remember the original location, which of course doesn't work anymore. To fix that, you can either run hash cmd which will lookup the command again, or run hash -r to forget all remembered locations (less efficient, but maybe faster to type ;-)

For more details, see help hash

0

Rename files with numeric padding

 $ perl -e 'for (@ARGV) { $o = $_; s/\d+/sprintf("%04d", $&)/e; print qq{mv "$o" "$_"\n}}'

— by Janos on Oct. 6, 2012, 1:38 p.m.

Explanation

Basically a one-liner perl script. Specify the files to rename as command line parameters, for example:

perl -e '.....' file1.jpg file2.jpg

In this example the files will be renamed to file0001.jpg and file0002.jpg, respectively. The script does not actually rename anything. It only prints the shell commands to execute that would perform the renaming. This way you can check first that the script would do, and if you want to actually do it, then pipe the output to sh like this:

perl -e '.....' file1.jpg file2.jpg | sh

What's happening in the one-liner perl script:

  • for (@ARGV) { ... } is a loop, where each command line argument is substituted into the auto-variable $_.
  • $o = $_ :: save the original filename
  • s/// :: perform pattern matching and replacement on $_
  • print qq{...} :: print the mv command, with correctly quoted arguments

Limitations

The script does not cover all corner cases. For example it will not work with files that have double-quotes in their names. In any case, it is safe to review the output of the script first before piping it to sh.

If your system has the rename command (Linux), then a shortcut to do the exact same thing is with:

rename 's/\d+/sprintf("%04d", $&)/e' *.jpg

It handles special characters better too.

0

Copy or create files with specific permissions and ownership

 $ install -b -m 600 /dev/null NEWFILE

— by Janos on Sept. 25, 2012, 2:20 p.m.

Explanation

This example creates a new (empty) file with permissions 600. You could also specify the owner and group using the -o and -g flags respectively.

Although you could accomplish the same for example by creating the file with touch and then change permissions with chmod and chown, or use umask to control the permissions of newly created files, those methods take multiple steps, while with install it is a single step.

You can also use install to copy multiple files to a directory with specified permissions like this:

install -m 600 -o jack -g wheel file1 file2 /path/to/existing/dir

0

Run command multiple times with a for loop and a sequence expression

 $ for i in {1..10}; do date; sleep 1; done

— by Janos on Aug. 19, 2012, 9:27 a.m.

Explanation

This is just a regular for loop with a sequence expression. A sequence expression has the form {x..y[..incr]}, where x and y are either integers or single characters, and incr an optional increment.

More examples:

  • {a..f} = a b c d e f
  • {a..f..2} = a c e
  • {0..1}{0..1} = 00 01 10 11

Limitations

Don't try a large range like {1..10000000000000000}, it may render your computer unusable until killed.

0

Clear the swap space forcing everything back to main memory in Linux

 $ sudo swapoff -a; sudo swapon -a

— by Janos on Aug. 14, 2012, 11:21 a.m.

Explanation

Note: if you don't have enough main memory the swapoff will fail.

Limitations

This works only in Linux.

0

Redirection operator to override the noclobber option

 $ some_command >| output.txt

— by Janos on Aug. 11, 2012, 9:21 a.m.

Explanation

Normally the > operator overwrites the target file.

If the noclobber option is set (using: set -o noclobber), the > operator will fail if the target file exists.

The >| overrides the noclobber setting and overwrites the target file.

If the noclobber option is not set, then >| is equivalent to >, naturally.

0

How to set the ip address in Solaris 11

 $ ipadm create-addr -T static -a 192.168.1.10/24 eth0/staticaddr

— by Janos on Aug. 3, 2012, 11:44 a.m.

Explanation

  • eth0 is the name of the network interface
  • ipadm show-if shows the list of network interfaces
  • staticaddr is a name you can choose

More details here: http://docs.oracle.com/cd/E19963-01/html/821-1458/gjwiq.html

0

Edit the Gimp launcher file to disable the splash screen

 $ sudo sed -i 's/^Exec=[^ ]*/& -s/' /usr/share/applications/gimp.desktop

— by Janos on June 30, 2012, 9:06 p.m.

Explanation

  • The -i flag of sed means to perform the command "in place", that is, save any changes in the input file. Use this flag with extreme caution, one wrong move and you can completely break the original file.
  • The regex pattern /^Exec=[^ ]*/ will match the line starting with Exec= followed by zero or more non-space characters.
  • In the replacement string, & -s, the & is replaced with whatever was matched, in this example probably something like Exec=gimp-2.8, after which we add a space and the -s flag which will effectively disable the splash screen when starting Gimp.

Limitations

The -i flag of sed works differently in GNU and BSD systems. This example works in GNU systems only. The equivalent in BSD is:

sudo sed -i '' 's/^Exec=[^ ]*/& -s/' /usr/share/applications/gimp.desktop

In any case, always be very careful when using the -i flag of sed.

0

`less` is more convenient with the `-F` flag

 $ less -F FILE1

— by Janos on June 25, 2012, 6:47 p.m.

Explanation

less is a "pager" program like more, with a lot of added features. By default, to exit less you have to press q. This can be annoying when viewing a small file that would fit on the screen.

The -F flag to the rescue! When started with the -F flag, less will quit if the entire input (whether from stdin or a file) fits on a single screen.

It has no effect whatsoever for longer input, so it is safe to add an alias for this:

alias less='less -F'

0

Append to a file text, a blank line, and the last line of another file

 $ { echo some text; echo; tail -n1 /var/log/apache2/error.log; } >> /path/to/file

— by Janos on June 22, 2012, 5:29 p.m.

Explanation

All the standard output from all the commands between the braces will be redirected.

0

Append to a file text, a blank line, and the last line of another file

 $ echo -e "From: me\n\n$(tail -n1 /var/log/apache2/error.log)" >> file

— by kevin on June 21, 2012, 8:18 p.m.

Explanation

  • -e option to echo makes it interpret '\n' as a newline
  • $(command) syntax runs a command, then uses its output in place

Limitations

The -e flag of echo doesn't work on all systems. In that case you can use printf instead.

0

Convert a list of terms in slug format to capitalized words

 $ sed -e 's/^./\U&/' -e 's/_./\U&/g' -e 's/_/ /g' /path/to/input

— by Janos on June 17, 2012, 7:54 a.m.

Explanation

The goal here is to take an input like this:

police_station
post_office
real_estate_agency

... and convert it to an output like this:

Police Station
Post Office
Real Estate Agency
  • -e ... the sed command can take several -e parameters, which will be executed one by one when processing each line in the input
  • The s/// command is a pattern replacement, and has the general format s/pattern/replacement/flags
  • s/^./\U&/ - replace the first letter of the line with uppercase version of the letter: \U means convert to uppercase, & is the matched string
  • s/_./\U&/g- replace _ and any letter followed by it. The g flag at the end means a "global" replacement, so all occurrences of the pattern _. will be replaced
  • s/_/ /g - replace all underscores with spaces
  • Input to sed can come from a list of files, or input redirection with <, or from a pipe.

0

Execute different commands with find depending on file type

 $ find /path/to/dir -type d -exec chmod 0755 '{}' \; -o -type f -exec chmod 0644 '{}' \;

— by Janos on June 17, 2012, 12:01 a.m.

Explanation

  • -type d -exec chmod 0755 '{}' \; for each directory, run chmod 0755
  • \; is to mark the end of the -exec
  • {} is replaced with the filename, we enclosed it in single quotes like this '{}' to handle spaces in filenames
  • -ological OR operator
  • -type f -exec chmod 0644 '{}' \; for each regular file, run chmod 0644

0

Convert m4a files to mp3 using faad and lame

 $ faad -o tmp.wav music.m4a && lame -b 192 tmp.wav music.mp3

— by Janos on June 14, 2012, 9:29 a.m.

Explanation

  • Step 1: convert m4a to wav using faad
  • Step 2: convert wav to mp3 using lame
  • -b 192 is the bitrate

Limitations

Neither faad nor lame are standard commands.

0

Write both stdout and stderr to the same file

 $ do_something.sh &> out.log

— by Janos on June 5, 2012, 11:34 a.m.

Explanation

Note: this is not always the same as:

do_something.sh >out.log 2>out.log

Using &> will ensure that the order of lines coming from stdout and stderr is preserved.

Limitations

This works in /bin/bash and may not work in /bin/sh or other stripped down variants of bash.

0

Create or mount an encrypted directory using encfs

 $ encfs -i 5 $PWD/raw $PWD/content

— by Janos on May 22, 2012, 12:21 a.m.

Explanation

The first time you run this, it will create an encrypted directory raw in the current working directory, and mount it on directory content in the same directory. It will ask a couple of questions:

  1. Create directory "raw" ? -- answer "y"
  2. Create directory "content" ? -- answer "y"
  3. Choose configuration mode -- press enter, or "p" for "paranoia mode"

The content directory will be visible and editable only by your user, and all the files you put inside will be saved encrypted under raw. The encrypted data is only visible when raw is mounted somewhere.

The -i 5 means the content directory will be automatically unmounted after being idle for 5 minutes.

You can manually unmount with umount ./content in Linux, and fusermount -u ./content in Mac OS.

To mount raw again, simply re-run the same command. This time it will only ask for the password.

Limitations

encfs is not a standard command/package. Major Linux distros have it in their repos, on Mac OS you can install using ports. (sudo port install encfs)

0

Run a never-ending process in the background in a way that you can check on its status anytime

 $ screen -d -m -S some_name ping my_router

— by Janos on May 17, 2012, 11:03 p.m.

Explanation

  • -d -m start screen in "detached" mode. This creates a new session but doesn't attach to it.
  • -S some_name gives the screen session a label, so you can easily re-attach to it with screen -R some_name
  • The shell prompt returns immediately, and of course you can logout too, the screen session will continue to run happily.
  • When the specified program exits (in this example ping), its screen window will also exit, and if there are no other windows in the screen session, then the screen session itself will also exit.