Linux: Shell script Tips

Table of Contents

1 Remove whitespace from delimiter at for statement

IFS has shell script delimiters (whitespace and newline by default). This is useful for renaming file which has a whitespace.

#!/bin/shfunc_a(){ echo “func_a” echo “arg1 = ${1}” echo “arg2 = ${2}” for arg in $@; do echo “arg = $arg”; done}func_b(){ echo “func_b” echo “arg1 = ${1}” echo “arg2 = ${2}” IFS=”” for arg in $@; do echo “arg = $arg”; done}func_a “This is arg1.” “This is arg2.”func_b “This is arg1.” “This is arg2.”

This script outputs as below. func_a separates with whitespace and func_b does not.

func_aarg1 = This is arg1.arg2 = This is arg2.arg = Thisarg = isarg = arg1.arg = Thisarg = isarg = arg2.func_barg1 = This is arg1.arg2 = This is arg2.arg = This is arg1.arg = This is arg2.

2 Remove if statement with && and ||

Using && and || avoids abuse of if statement.

The following syntax like perl’s “open or die” with && and || provides if statement. But the order of && and || cannot be reversed.

$ true && echo “true” || echo “false”true$ false && echo “true” || echo “false”false

If command after && is failed, command after || will be run.

$ true && false || echo “false”false

Multiple && and || are also useful.

$ true && true && echo “true”true$ false || false || echo “false”false

3 Treat echo’s outputs as return value

You can assign echo’s outputs to variable.

#!/bin/shdiv(){ [ ${2} -eq 0 ] && return 1 echo $(expr ${1} / ${2})}val=$(div 10 5) && echo “10 / 5 = ${val}”val=$(div 10 0) && echo “10 / 0 = ${val}”

This script outputs as below. When div function returns 0, assigned value will output.

10 / 5 = 2

4 Use $(cmd) rather than `cmd`

$(cmd) can be nested as it is.

$(cmd1 $(cmd2 $(cmd3)))

Nested `cmd` needs nested escape character.

`cmd1 `cmd2 \`cmd3\` “

5 (cmd), $(cmd) and `cmd` is child process

(cmd), $(cmd) and `cmd` is child process. The difference with & is to wait for terminate.

call exit command in child process does not terminate parent. And parent process cannot access assigned value in child.

#!/bin/shfunc(){ echo “prev exit” exit 1 echo “post exit” return 0}(echo “prev exit”; exit 1; echo “post exit”)echo “ret = $?”msg=$(func)echo “ret = $?, msg = ${msg}”

This script outputs as below.

prev exitret = 1ret = 1, msg = prev exit

6 Use echo and return error value

While echo’s output can be redirect to stderr, echo’s return value will be true except serious error which output does not work like I/O error. If you want to output error message (echo “error”) and return error value (cmd) for error case (false), echo’s return value will be wrong. The following “cmd” does not run except echo’s serious error.

$ false || echo “error” 1>&2 || cmd

Using echo and exit with “()” provides echo’s output and return error value.

#!/bin/shdo_echo(){ false || echo “error” 1>&2 || return 1}do_echo_and_exit(){ false || (echo “error” 1>&2 && exit 1) || return 1}do_echo || echo “do_echo is failed” 1>&2do_echo_and_exit || echo “do_echo_and_exit is failed” 1>&2

This script outputs as below.

errorerrordo_echo_and_exit is failed

The error function which outputs error message and returns error value is useful too.

#!/bin/sherror(){ echo “$@” 1>&2 return 1}false || error “error” || echo “failed” 1>&2

This script outputs as below.


7 Function declaration in one line

You can define function declaration in one line with semicolon.

func() { echo “func”; }

8 Reflection with type

For example, there is a case statement which will call func_x function with value, and the definition of func_x will increase in the future.

In this case, you need to define func_x (callee) and also modify case statement (caller).

#!/bin/shfunc_a() { echo “func_a is called”; }func_b() { echo “func_b is called”; }read namecase ${name} in a) func_a;; b) func_b;; *) echo “func_${name} is not defined”;;esac

type provides reflection code, modifying caller is unnecessary.

#!/bin/shfunc_a() { echo “func_a is called”; }func_b() { echo “func_b is called”; }read nametype func_${name} > /dev/null 2>&1 && func_${name} || echo “func_${name} is not defined”

9 Debug with /bin/sh -x

sh -x option outputs running statement. Loaded shell script with “.” is applied too.

$ cat!/bin/sha=1[ ${a} -eq 1 ] && echo ${a}$ sh -x a=1+ [ 1 -eq 1 ]+ echo 11

Changing shebang to /bin/sh -x is the same. This is useful for shell script which will be started automatically.

#!/bin/sh -x

Android | Linux | SDL - Narrow Escape