Difference between revisions of "Bash notes"
Line 44: | Line 44: | ||
* ${foo=text} - If $foo exists and is not null then return $foo. If $foo doesn't exist then create it and set value to text. | * ${foo=text} - If $foo exists and is not null then return $foo. If $foo doesn't exist then create it and set value to text. | ||
+ | === brace expansion versus backtick expansion for command substitution === | ||
+ | |||
+ | Backtick expansion works in even the oldest Bourne shell variant. It cannot best nested. | ||
+ | <pre> | ||
+ | echo `ls /boot/` | ||
+ | </pre> | ||
+ | |||
+ | Brace expansion works in any POSIX Bourne shell (sh, ash, dash, bash, etc...). Brace expansion can be nested. The following could not be done with backtick expansion: | ||
+ | |||
+ | <pre> | ||
+ | echo $(ls /boot/*$(uname -r)*) | ||
+ | </pre> | ||
+ | |||
+ | === quote output in echo to preserve new lines === | ||
+ | |||
+ | Echo automatically converts new lines to spaces. This can be useful for substituting in loops. | ||
+ | |||
+ | This converts new lines to spaces: | ||
+ | |||
+ | <pre> | ||
+ | echo $(ls /boot/) | ||
+ | </pre> | ||
+ | |||
+ | The following preserves the new lines output from `ls`: | ||
+ | |||
+ | <pre> | ||
+ | echo "$(ls /boot/)" | ||
+ | </pre> | ||
== absolute and relative paths == | == absolute and relative paths == |
Revision as of 12:17, 12 February 2009
Contents
- 1 Turn off bash history for a session
- 2 Rename a group of files by extension
- 3 Special Shell Variables
- 4 Variable Expansion and Substitution
- 5 absolute and relative paths
- 6 Statements
- 7 get input from user
- 8 get yes/no input feedback from user
- 9 check if running as root
- 10 check if process is running
Turn off bash history for a session
set +o history
Rename a group of files by extension
For example, rename all images from foo.jpg to foo_2.jpg.
This is somewhat more clear:
for filename in *.jpg ; do mv $filename `basename $filename .jpg`_2.jpg; done
This is more "correct" and doesn't require `basename`:
for filename in *.jpg ; do mv $filename ${filename%.jpg}_2.jpg; done
Special Shell Variables
- $*
- all parameters separated by the first character of $IFS
- $@
- all parameters quoted
- $#
- the number of parameters
- $?
- exit status of last command
- $-
- option flags set `set` or passed to shell
- $$
- pid of this shell
- $!
- pid of last background command
- $0
- name of the shell or script
- $_
- arguments of last command
Variable Expansion and Substitution
Bash can do some freaky things with variables. It can do lots of other substitutions. See "Parameter Expansion" in the Bash man page.
- ${foo#pattern} - deletes the shortest possible match from the left
- ${foo##pattern} - deletes the longest possible match from the left
- ${foo%pattern} - deletes the shortest possible match from the right
- ${foo%%pattern} - deletes the longest possible match from the right
- ${foo=text} - If $foo exists and is not null then return $foo. If $foo doesn't exist then create it and set value to text.
brace expansion versus backtick expansion for command substitution
Backtick expansion works in even the oldest Bourne shell variant. It cannot best nested.
echo `ls /boot/`
Brace expansion works in any POSIX Bourne shell (sh, ash, dash, bash, etc...). Brace expansion can be nested. The following could not be done with backtick expansion:
echo $(ls /boot/*$(uname -r)*)
quote output in echo to preserve new lines
Echo automatically converts new lines to spaces. This can be useful for substituting in loops.
This converts new lines to spaces:
echo $(ls /boot/)
The following preserves the new lines output from `ls`:
echo "$(ls /boot/)"
absolute and relative paths
Convert a relative path to a absolute path. It is stupid that there is not a command to do this. This does not effect the current working directory. This finds the absolute full path to $1:
echo "absolute path: `cd $1; pwd`"
Get the absolute path of the currently running script.
abs_path_here=`echo -n \`pwd\` ;( [ \`dirname \$0\` == '.' ] && echo ) || echo “/\`dirname \$0\`”`
Statements
Loop on filenames in a directory
for foo in *; do { echo ${foo} }; done
Loop on lines in a file
for foo in $(cat data_file.txt); do { echo ${foo} }; done
while loop
This is kind of like `watch`:
while sleep 1; do lsof|grep -i Maildir; done
get input from user
In bash, the builtin command, read, is used to get input from a user. By default it will read input from stdin, but there are many situation when you want to get input from the user's TTY instead of stdin. Two examples. Example A: you piped output from another program into your script then it would try to read input from the pipeline (what it sees as stdin). Example B: you are building an embedded Linux system where you want a boot script to ask the user for input before the console TTY has been opened and attached to stdin for a shell or login daemon.
read YN < /dev/tty0 read YN < /dev/tty read YN < /dev/tty2
which tty?
If you switch to a console screen (CTRL-ALT-F1 and ALT-F7 to return to X11) and then you login you will see that you now become the owner of /dev/tty1. Switch to a console and login then switch back to X11 (ALT-F7) and from a shell, you see that you now own /dev/tty1. When you logout the tty1 will return to root ownership.
$ ll /dev/tty1 crw------- 1 root root 4, 1 2009-01-04 06:02 /dev/tty1 $ ll /dev/tty1 crw------- 1 my_user tty 4, 1 2009-01-04 06:03 /dev/tty1
get yes/no input feedback from user
YES=1 NO=0 INVALID=-1 yesno() { echo -e $1 VALID_YN=$FALSE YN= rval= echo -e " [y/n] \c" read YN if [ -z "$YN" ] then VALID_YN=$FALSE rval=$INVALID else case "$YN" in [Yy]*) VALID_YN=$TRUE rval=$YES ;; [Nn]*) VALID_YN=$TRUE rval=$NO ;; *) VALID_YN=$FALSE rval=$INVALID ;; esac fi if [ $rval -eq $INVALID ] then echo "Invalid Response..." fi return $rval }
check if running as root
if [ $(id -u) -eq 0 ]; then echo "You are root." fi
Or check if not root...
if [ $(id -u) -ne 0 ]; then echo "You must be root to run this." fi
check if process is running
Show the pids of all processes with name "openvpn":
ps -C openvpn -o pid=
Show if a process with pid=12345 is running:
kill -0 12345 echo $?
Check if a process with a given command name and pid is still running. For example, check if ssh process is running with pid 12345: "checkpid ssh 12345". Checkpid script:
#!/bin/sh # example: checkpid ssh 12345 CMD=$1 PID=$2 for QPID in $(ps -C $CMD -o pid=); do if [ $QPID = $PID ]; then echo "running" exit 0 fi done echo "not running" exit 1