112
votes

I would like to open a discussion that would accumulate your Linux command line (CLI) best practices and tips.

I've searched for such a discussion to share the below comment but haven't found one, hence this post.

I hope we all could learn from this.

You are welcome to share your Bash tips, grep, sed, AWK, /proc and all other related Linux/Unix system administration, shell programming best practices for the benefit of us all.

9
  • Why Linux only? Many tips may be useful on almost all flavours of Unix.
    – mouviciel
    Mar 2, 2009 at 19:49
  • This question might be a tad broad - there is enough to Linux/Unix command line best practices to fill entire books...
    – Jonik
    Mar 2, 2009 at 19:50
  • I agree that unix tips that can be applied to linux also are very much welcome, I've written linux because A. This is what we work with here. B. because it's gaining a more wider public exposure then unix in recent years. Mar 2, 2009 at 19:57
  • I think it's a great idea to comiple a list of the most useful and interesting commands that people use.
    – Shane
    Mar 2, 2009 at 19:57
  • Are any of these relevant? refspecs.freestandards.org
    – S.Lott
    Mar 2, 2009 at 19:58

85 Answers 85

1 2
3
1
vote

I'm moving towards never typing "rm" at a command prompt. Instead, I type "ls", and if I like the list of removed files I edit the command (easily possible with bash and ksh).

Edit to add something from the comments: "rm -i" will prompt for each deletion, which accomplishes the same purpose. Thanks!

5
  • Please explain, I can't understand what you mean? Mar 2, 2009 at 20:24
  • Typing something like "rm *.txt.bak" is a little error-prone; if you type "rm * .txt.bak" by mistake you're in trouble. Therefore, I'll type "ls *.txt.bak" to see if I'm selecting the files I think I am; then I use bash shell command-line editing to substitute "rm" for "ls". Mar 2, 2009 at 20:44
  • How do you do the command-line substitution? There must be a faster way than hitting up, home, delete, delete, r, m.
    – dotjoe
    Mar 2, 2009 at 22:23
  • I don't know of a faster way. I type faster and better than most people I hang out with, and it seems that I am willing to type more than they are. I think that in csh and tcsh ^ls^rm or something like that worked. Mar 3, 2009 at 14:36
  • Using 'rm -i filename' works for me. It will prompt me to remove the file. I actually aliased rm to 'rm -i'.
    – gpojd
    Mar 3, 2009 at 16:54
1
vote

You can do some simple networking with bash (credit to this page and man bash):

cat < /dev/tcp/time.nist.gov/13

Yes, writing to and simultaneous reading-writing is also possible.

2
  • Alas, Bash from Ubuntu doesn't seem to have this feature enabled :-( Wait for newer version.
    – kyku
    Mar 5, 2009 at 8:11
  • I beleive this is because Bash from Ubuntu isn't compiled with the option to enable networking. Don't know what reasons keep them from enabling it. But I couldn't find a proper use for this feature anyway. :)
    – Eugene Morozov
    Mar 5, 2009 at 11:23
1
vote

Above all, understand anything you see in the internetz before trying it out in your dev box.

1
1
vote

Every now and then neither of:

find . -exec ...
find . -print0 | xargs ...
for i in *.png; do ... done

works for processing a list of files, since one needs the combined power of find, NULL separated filenames as well as plain shell loops. The solution is this little bit of bash code:

find . -print0 | while read -r -d $'\0' filename; do echo $filename; done

That allows one to process NULL separated files in a normal loop.

2
  • What is the problem with the third? for i in *.png; do...done?
    – Juliano
    Mar 29, 2009 at 3:16
  • GNU Parallel gnu.org/software/parallel seems to be better suited for this, as it can run jobs in parallel. The while-read loop can be rewitten as: find . -print0 | parallel echo Watch the intro video: youtube.com/watch?v=OpaiGYxkSuQ
    – Ole Tange
    Jun 22, 2010 at 12:09
1
vote

Shell-fu is a place for storing, moderating and propagating command line tips and tricks. A bit like StackOverflow, but solely for shell. You'll find plenty of answers to this question there.

1
vote

Another trick:

When I want to make a bash alias, I just make a bash script on my user bin folder.

For instance, instead of adding the following line to my .bashrc,

alias make-symlink='ln -s -iv'

I'd make the following script and save it as ~/bin/make-symlink

#!/bin/bash                                                                     
ln -s -iv "$@"

, once the script is made executable (chmod +x), it's like I have a new alias.

Now make-symlink can be used in xargs. Also when you use a different shell (ZSH, FISH, IPYTHON, ...), make-symlink is there too.

If you use emacs, you might want to add the following to your emacs init file.

;; Make scripts executable on save                                              
(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
1
vote

The 'tee' command is really useful for when you are outputting to a file and want to see the progress at the same time. This is especially helpful for when you are logging output to a file and need to watch it as it progresses.

Instead of doing something like:

./program > file &
tail -f file

You can use the tee command on one line:

./program | tee file
1
vote

I like to keep track of everything I do. One command that I learned in college was 'script'. This takes any output on your terminal and logs it to a file. What I didn't learn in college is how to make every terminal a script. Now I have this in my .login file:

exec script ~/.typescript/`date +%Y%m%d%H%M%S`.$$

Make sure that ~/.typescript/ exists before you add that to the end of your .login file. :)

1
vote
  • For smaller directory trees with documentation to browse

    find .
    
  • To empty a file from shell

    > file.txt
    
  • To return to my home directory

    cd
    
1
vote

IMHO, *nix most important command ever is... man :)

Almost everything one needs to know can be found with man and using man prevents us from interrupting our co-workers. And dealing with interruptions is one of our biggest concerns...

1
vote

I found Git version control to be:

  • Snappy
  • A pleasure to use
  • Useful for a projects of almost any size (100K to 100GB; 1 to 100k files)

Here is how I do it:

# Create new repository
# (for now, it will live in .git/ - a single directory)
git init

# Commit all I got so far
git add .
git commit

# Add new or modified files manually
git add *.c
git status
git commit

# Add all modified files
git status
git commit -a

# Redo last commit
git commit -a --amend

# View log
git log

# Reset everything (files and git history) back to 
# what it was at 96223554b3e3b787270b1f216c19ae38e6f83ca5
git branch this-was-a-mistake
git reset --hard 9622

# Everything is back in time
ls
git log
1
vote

Easy sums/averages/grouping with awk:

cat tests
ABC 50
DEF 70
XYZ 20
DEF 100
MNP 60
ABC 30

cat tests | awk '{sums[$1] += $2; tot += $2; qty++}\
   END { for (i in sums) 
     printf("%s %s\n", i, sums[i]); 
     printf("Total: %d\nAverage: %0.2f\n", tot, tot/qty)} ' 
MNP 60
ABC 80
XYZ 20
DEF 170
Total: 330
Average: 55.00
1
vote

I dont these commands are in the above list...!!!

  1. find . -name .svn -type d |xargs rm -rf

    Remove all .svn folders

  2. bash -x script.sh

    print line and execute it in BASH

  3. Ctrl + [

    the same as [Esc] in vim

  4. shopt -s autocd

    Automaticly cd into directory

  5. df -i

    View the current number of free/used inodes in a file system

  6. sudo !!

    Run the last command as root

  7. python -m SimpleHTTPServer

    Serve current directory tree at http://$HOSTNAME:8000/

  8. netstat -tlnp

    Lists all listening ports together with the PID of the associated process

  9. Below are some ways to number input.txt:

    cat -n

    $ cat -n input.txt 1 123 2 3 456 4 5 789 6 7 8 abc 9 10 def 11 12 ghi

0
votes

Output Redirection. When you're running something apend

> ~log.txt

to capture the output for later. Append

>& error_and_log.txt

for errors as well.

0
votes

pushd and popd to temporarily switch to different directories.

So

pushd ~/tmp

will move you to that directory, but push your current location to a stack (so it can be nested).

Then

popd

to return to the previous location.

0
votes

Turn on inline mode for tab completion for Bash:

http://codesnippets.joyent.com/posts/show/1690

0
votes

To open remote X application on you local machine do:

ssh -X remoteuser@removeHost
konsole

This allows quickly viewing graphical applications running on remote host yet using your machine as the graphical server.

0
votes

Copy selected text:

CTRL + SHIFT + C

...and paste it:

CTRL + SHIFT + V
1
  • You can paste the last selected text by clicking on the middle mouse button. May 4, 2009 at 15:54
0
votes

In bash to close file descriptors: FD>&-

Close stderr:

$ function echostderr() { echo $1 >&2; }
$ echostderr "now you see me"
now you see me
$ echostderr "now you don't" 2>&-
$ 

Or inside a script:

$ function echostderr() { exec 2>&-; echo $1 >&2; }
$ echostderr "now you don't"
$ 
0
votes

ALWAYS start any command or pipeline with # (comment) and remove it when you finish writing the command. Gives you a 2nd chance at spotting rm -rf / like things.

0
votes

Here are Collection of Linux, UNIX User Management Commands http://www.linuxconfig.net/2009/11/16/linux-unix-user-management-commands.html

0
votes

Meta+. in bash for cycling through the last argument from previous commands. Great for running tail and grep in various combinations.

1
  • Note for OS X users: In Terminal, meta needs to be enabled under the Keyboard settings before this will work.
    – Jeremy M
    Jul 14, 2010 at 17:27
0
votes

CTRL+] x to forward search for a character "x", and Meta, CTRL+] x for backward search. On most systems, Meta can be ESC or ALT. For ESC, you press ESC then release, then combine CTRL and ], and then press the character to search for. For ALT, press down CTRL + ALT + ] at the same time, then the target character.

I find it's useful when editing history command.

For very long and very complicated command. I use fc to open vi(probably actually vim on linux) to edit the command.

1
  • 1
    For long command editng, in bash at least, you can 'set -o vi' to enable vi-style keybindings directly in your shell.
    – pboin
    Oct 25, 2010 at 14:49
0
votes

To rename a multiple files in a similar fashion I found the following script very useful and robust over the years.

It just puts the output of ls into your favorite text editor. You just modify the text, save, close. The files are renamed accordingly.

It's especially great when you combine this with Vi column editing (Ctrl-v, select a block, I to insert before or A to insert after, type text, Esc).

#!/usr/bin/ruby

RM = '/bin/rm'
MV = '/bin/mv'

from = Dir.entries('.').sort; from.delete('.'); from.delete('..')
from.sort!

from.delete_if {|i| i =~ /^\./} # Hidden files

tmp = "/tmp/renamer.#{Time.now.to_i}.#{(rand * 1000).to_i}"

File.open(tmp, 'w') do |f|
  from.each {|i| f.puts i}
end

ENV['EDITOR'] = 'vi' if ENV['EDITOR'].nil?
system("#{ENV['EDITOR']} #{tmp}")

to = File.open(tmp) {|f| f.readlines.collect{|l| l.chomp}}
`#{RM} #{tmp}`

if to.size != from.size
  STDERR.puts "renamer: ERROR: number of lines changed"
  exit(1)
end

from.each_with_index do |f, i|
  puts `#{MV} -v --interactive "#{f}" "#{to[i]}"` unless f == to[i]
end

I call this script renamer.

0
votes

To copy part of a file system to a new hard disk one can use

mkfs.ext4 /dev/sdb
mkdir /mnt/newhd
mount /dev/sdb /mnt/newhd/
rsync -av --hard-links --acls --one-file-system --xattrs /home/maxim/ /mnt/newhd/
echo '/dev/sdb /home/maxim ext4 defaults,user_xattr,noatime 0 1' >> /etc/fstab
1 2
3

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .