16

We've had these for a lot of other languages. The one for C/C++ was quite popular, so was the equivalent for Python. I thought one for BASH would be interesting too.

Community
  • 1
  • 1

21 Answers21

18

There's cd - to go to the previously-visited directory:

/usr/local/bin> cd /i/am/a/banana
/i/am/a/banana> cd -
/usr/local/bin>

...and then there are all those useful incarnations of the BASH for-loop:

for file in *.txt; do ls $file; done

for item in $(echo foo bar baz); do echo $item; done

for num in {0..9}; do echo $num; done
Nate Kohl
  • 35,264
  • 10
  • 43
  • 55
  • 2
    I never knew about `cd -`, thanks! That looks like it might help. – Zifre Jun 10 '09 at 11:08
  • 2
    ick... I always hate seeing `seq i j` and `jot j i`. Modern bash has range expansions: for n in {1..100}; do ... – guns Jul 30 '09 at 07:28
  • 2
    why do you have a directory called /i/am/a/banana ? ;) – Stefano Borini Jan 13 '10 at 08:16
  • 1
    @Stefano: http://www.youtube.com/watch?v=MuOvqeABHvQ – Nate Kohl Jan 13 '10 at 13:44
  • 1
    Avoid backticks, and use `for item in $(echo foo bar baz)` because: a) $(..$(..)) is easily nestable, b) backticks can be, dependent on fonts, be confused with apostrophes, and c) you need backticks to make code-layout in comments on SO. – user unknown Aug 15 '11 at 16:50
  • @user unknown: excellent suggestions; I've updated this answer. – Nate Kohl Aug 15 '11 at 17:23
  • I know that `for file in *.txt; do ls $file; done` is meant as a simple example, but of course you would do `ls *.txt` directly - you would need an example with 2 invocations of '$file'. :) – user unknown Aug 15 '11 at 17:31
14

In a BASH script, assign an argument to variable but provide a default if it exists:

MYVAR=${1:-default}

$MYVAR will contain the first argument if one was given else "default".

Robert Gowland
  • 7,677
  • 6
  • 40
  • 58
  • 1
    Not to mention this snippet's cousin: MYVAR=${OTHER_VAR:=default} which sets the value of OTHER_VAR to default if it is unset. Above only uses the default only uses the default value in this instance and leaves $1 unset. – Rob Wells Jun 10 '09 at 11:28
11

G'day,

My favourite, and it's applicable to other shells that support aliases, is the simple way of temporarily disabling an alias by prepending a backslash to a command.

So:

alias rm='rm -i'

would always give you interactive mode when entering rm, entering

\rm

on the command line bypasses the alias.

HTH

cheers,

Rob Wells
  • 36,220
  • 13
  • 81
  • 146
7

This is not so useful, but really interesting:

history | awk '{print $2}' | awk 'BEGIN {FS="|"}{print $1}' | sort | uniq -c | sort -n | tail | sort -nr

It prints the 10 most used commands.

EDIT: This question is really similar to this.

Community
  • 1
  • 1
Fernando Martin
  • 512
  • 1
  • 6
  • 21
5

Found this somewhere on the net a long time ago:

function bashtips {
cat <<EOF
DIRECTORIES
-----------
~-      Previous working directory
pushd tmp   Push tmp && cd tmp
popd        Pop && cd

GLOBBING AND OUTPUT SUBSTITUTION
--------------------------------
ls a[b-dx]e Globs abe, ace, ade, axe
ls a{c,bl}e Globs ace, able
\$(ls)      \`ls\` (but nestable!)

HISTORY MANIPULATION
--------------------
!!      Last command
!?foo       Last command containing \`foo'
^foo^bar^   Last command containing \`foo', but substitute \`bar'
!!:0        Last command word
!!:^        Last command's first argument
!\$     Last command's last argument
!!:*        Last command's arguments
!!:x-y      Arguments x to y of last command
C-s     search forwards in history
C-r     search backwards in history

LINE EDITING
------------
M-d     kill to end of word
C-w     kill to beginning of word
C-k     kill to end of line
C-u     kill to beginning of line
M-r     revert all modifications to current line
C-]     search forwards in line
M-C-]       search backwards in line
C-t     transpose characters
M-t     transpose words
M-u     uppercase word
M-l     lowercase word
M-c     capitalize word

COMPLETION
----------
M-/     complete filename
M-~     complete user name
M-@     complete host name
M-\$        complete variable name
M-!     complete command name
M-^     complete history
EOF
}
3

Add a space (or other delimiter) only if a variable is set, in order to avoid ugly unnecessary spaces.

$ first=Joe
$ last=      # last name blank, the following echoes a space before the period
$ echo "Hello, $first $last. Welcome to..."
Hello, Joe . Welcome to...

$ echo "Hello, $first${last:+ $last}. Welcome to..."
Hello, Joe. Welcome to...

$ last=Green
$ echo "Hello, $first${last:+ $last}. Welcome to..."
Hello, Joe Green. Welcome to...
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
2

Here is a nice grep expression to remove blank lines and comment lines:

grep -v '^[ \t]*$\|^[ \t]*#' /etc/ssh/sshd_config

The above will display the used settings in sshd_config without any clutter.

rzymek
  • 9,064
  • 2
  • 45
  • 59
2

To remove .svn directories you may also use the combination 'find...-prune...-exec...' (without xargs):

# tested on Mac OS X

find -x -E . \( -type d -regex '.*/\.svn/*.*' -prune \) -ls  # test

find -x -E . \( -type d -regex '.*/\.svn/*.*' -prune \) -exec /bin/rm -PRfv '{}' \; 
  • 1
    I think you don't need `-exec rm` for gnu-find, since there is a -delete (but not sure about -PRfv :=verbose, force, Recursive, P?). And you don't need to mask `{}` - else I would enjoy to upvote and accept it an answer here: http://unix.stackexchange.com/q/8647/4485 – user unknown Aug 15 '11 at 16:58
2

Here is another one:

#!/bin/bash

# Shows the full path of files, good for copy pasting and for when
# listing the full paths is necessary.

# Usage: Run in the working directory (no path), otherwise takes the
# same file specification as ls.

for file in $(ls "$@"); do
        echo -n $(pwd)
        [[ $(pwd) != "/" ]] && echo -n /
        echo $file
done
2

At the beginning of a script that must be run as root:

if [ `id -u` != 0 ]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi
amarillion
  • 24,487
  • 15
  • 68
  • 80
  • Nice one! I've been wondering about how to detect root from a script. :-) –  Jun 10 '09 at 14:46
  • 1
    The `!= 0` is superfluous, and it can be shortened to `test $(id -u) && echo "This ..." && exit 1` – user unknown Aug 15 '11 at 17:02
  • @userunknown: That line makes no sense. Won't the `id -u` answer with the user id, and regardless have an exit status of 0. unless you use a root id of 0 as the status somehow... that's what the 1>&2... in this interesting case... I check that out – J. M. Becker Dec 18 '11 at 08:02
  • ... actually, if you don't care about using bashisms... You could write it like this also. `(( \`id -u\` )) && echo "Must be root" && exit 1` – J. M. Becker Dec 18 '11 at 08:19
1

I use this one a lot in conjunction with Java development:

#!/bin/sh

if [ "$1" == "" ] || [ "$2" == "" ]; then
echo "Usage jarfinder.sh  "
    exit
fi

SEARCH=`echo $2 | sed -e 's/[\\\/]/./g'`

echo Searching jars and zips in $1 for "$SEARCH"

find $1 -type f -printf "'%p'\n" | egrep "\.(jar|zip)'$" | sed -e "s/\(.*\)/echo \1 ; jar tvf \1 | sed -e 's\/^\/ \/' | grep -i \"$SEARCH\"/" | sh

which I keep in my collection of handy scripts.

I also use this one-liner a lot:

find . -name "*.java" | xargs grep -li "yadayada"

end this one:

find . -name "*.java" | sed -e 's+\(.*\)+echo \1 ; yada_cmd \1+' | sh
Don Branson
  • 13,631
  • 10
  • 59
  • 101
1
 !find:p  ......... show last find command - not execute
 # create one dir and go to
 echo 'mkcd() { mkdir -p "$@" && cd $_; }' >> ~/.bashrc  

 # backup file in single command
 cp /path/too/long/to/file{,.backup}
SergioAraujo
  • 11,069
  • 3
  • 50
  • 40
1

If you like to have your current working directory in your prompt ($PS1), are running in a terminal with only 80 columns, and sometimes work in really deep hierarchies, you can end up with a prompt that takes all but about 5 characters of your line. In that case, the following declarations are helpful:

PS1='${PWD##$PREFIX}$ '

PREFIX='' export PREFIX
prefix () {
  PREFIX="$1"
}
prefix '*/'

The prefix '*/' call will set your prompt to only contain the last directory element of your current working directory (instead of the complete path). If you want to see the entire path, call prefix with no arguments.

Gordon Broom
  • 300
  • 1
  • 7
1

I love the backtick operator.

gcc `pkg-config <package> --cflags` -o foo.o -c foo.c

And:

hd `whereis -b ls | sed "s/ls: //"` | head

Knowing me, I've missed a more efficient way of 'head'ing the hexdump of a binary which you don't know the location of... oh, and as is fairly obvious, "ls" can be swapped out with a variable so in a script it would go something like:

#!/bin/bash
hd `whereis -b $1 | sed "s/$1: //"` | head

The practical usefulness of the above is fairly limited but it demonstrates the versatility of the backtick operator (and the bash shell) fairly well, in my humble opinion.

Chris Browne
  • 1,582
  • 3
  • 15
  • 33
1

We develop websites and store code for them in SVN. When moving to production we don't want the .svn directories to show up. The following code recurses directories and removes unwanted ones (could be used for any unwanted directories). Not strictly bash but useful nonetheless.

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

execute from the top most path in the product ... of course be careful as executed in the wrong place could cause very bad things to happen.

You could also do a regular file by changing -type d to -type f

Cfreak
  • 19,191
  • 6
  • 49
  • 60
0

I use this to indent source code by four spaces and copying the result to the clipboard in X:

cat src/Something.java | sed -e 's/^/    /g' | xsel

Now Something.java is ready to be pasted by middle clicking. I know I can reduce the expression by one pipe and remove the cat, but I like it this way as I find it easier edit the beginning when re-using the expression.

0

An effective (and intuitive) way to get a full canonical file path given a specified file. This would resolve all cases of symbolic links, relative file references, etc.

full_path="$(cd $(/usr/bin/dirname "$file"); pwd -P)/$(/usr/bin/basename "$file")"
0

I use this to launch apps in their own xterm window (or not) from the same link.

#!/bin/bash
#
# cli_app launcher -- detects where u are launching from;  gui/tty
# 

dev=`/usr/bin/tty`
case $dev in
/dev/pts/0 | /dev/pts/1) xterm -e /home/user/bin/cli_app ;; ## opens gui terminal
*) /home/user/bin/cli_app ;;                                 ## opens where u are
esac

# eof #
ongoto
  • 9
  • 2
0

To change all files in ~ which are owned by the group vboxusers to be owned by the user group kent instead, I created something. But as it had a weakness in using xargs I'm changing it to the solution proposed in the comment to this answer:

$ find ~ -group vboxusers -exec chown kent:kent {} \;
0

Too long to include in total, but the solutions to How do I manipulate $PATH elements in shell scripts? are quite useful to me...

Community
  • 1
  • 1
dmckee --- ex-moderator kitten
  • 98,632
  • 24
  • 142
  • 234
0
: > truncate-file-to-zero-bytes.txt    # without changing its permissions  

See: codesnippets.joyent.com/posts/show/2067