条件语句if的基本格式

if command; then
  command
  command
  ...
fi

如果command;exit status为0,则执行thenfi之间的代码

Exit Status

任何程序运行结束后都会向shell返回一个数值(exit status)来表示程序的执行情况。
一般返回0表示执行成功,其它值则表示不同类型的错误

变量$?始终保存shell中最后一次执行的命令的exit status

一个检测某用户是否登录的程序

user="$1"

if who | grep "^$user " > /dev/null
then
  echo "$user is logged on"
fi

因为grep会将匹配的行输出,所以使用/dev/null将输出结果指向系统的garbage can。 任何用户都可以读写此文件,但读取不到任何内容,写入的内容也立即消失。 从而时grep语句在shell中不输出任何内容。
echo语句的锁进不是必须的,只是为了增加可读性

test命令

test expression

test首先执行expression语句,如果结果为true则返回的exit status为0,否则为非0值

字符串操作

判定两个字符串是否相同

test "$name" = luna

注意两个运算量($nameluna)和运算符(=)都是作为参数传给test命令的,也就是说=两边都要加空格

由于变量值替换发生在传参数之前,所以使用双引号是很好的习惯。如果变量$name的值为空,无双引号时则会报错

$ name=
$ test $name = luna
# sh: test: argument expected

这是因为传给test的只有=luna两个参数,所以报错
而如果使用双引号则不会有问题,传给test仍是三个参数null, =, luna

Operator Returns TRUE(exit status of 0) if
string1 = string2 string1 is identical to string2
string1 != string2 string1 is not identical to string2
string string is not null
-n string string is not null(and string must be seen by test)(nonzero length)
-z string string is null(and string must be seen by test)(zero length)
$ echo $symbol
=
$ test -z "$symbol"
sh: test: argument expected

这是因为=的优先级高于-z。可以使用以下方式解决

test X"$symbol" = X

如果$symbol是空则返回true,否则返回false

test的另一种格式

test expression
[ expression ]

以上两条语句等价。[实际上是test命令的另一个名字(命令名可以不包含字母),但是你必须在结尾使用]结束。 所以在expression[, ]之间必须加空格

整数操作

Operator Returns TRUE(exit status of 0) if
int1 -eq int2 int1 is equal to int2
int1 -ge int2 int1 is greater than or equal to int2
int1 -gt int2 int1 is greater than int2
int1 -le int2 int1 is less than or equal to int2
int1 -lt int2 int1 is less than int2
int1 -ne int2 int1 is not equal to int2

文件操作

shell有多种关于文件的test操作,以下为常用的几种

Operator Returns TRUE(exit status of 0) if
-d file file is a directory
-e file file exits
-f file file is an ordinary file
-r file file is readable by the process
-s file file has nonzero length(not empty file)
-w file file is writable by the process
-x file file is executable
-L file file is a symbolic link

逻辑取反操作符!

对任何test的运算结果取反

[ ! -f "$file" ]

逻辑与操作符-a

[ "$count" -ge 0 -a "$count" - lt 10 ]

使用最短路径原则,如果前面的值结果为false,则立即返回结果不进行后续计算

括号

[ \( "$count" -ge 0 \) -a \( "$count" - lt 10 \) ]

注意,括号左右必须都加空格

逻辑或操作符-o

优先级比-a

[ -n "$file" -o -r $HOME/file ]

else结构

if command
then
  command
else
  command
fi
if [ "$#" -ne 1 ]
then
  echo "Incorrect number of argument"
  echo "Usage: on user"
else
  user="$1"
  if who | grep "^$user " > /dev/null
  then
    echo "$user is logged on"
  else
    echo "$user is not logged on"
  fi
fi

exit命令

exit n

exit可以立即结束结束你的程序,并将n最为exit status的值返回。如果没有知名n的值,则相当于exit $?

if [ "$#" -ne 1 ]
then
  echo "Incorrect number of argument"
  echo "Usage: rem name"
  exit 1
fi

grep -v "$1" phonebook > /temp/phonebook
mv /temp/phonebook phonebook

elif结构

if [ condition ]; then
  command
elif [ condition ]; then
  command
else
  command
fi
if [ "$#" -ne 1 ]
then
  echo "Incorrect number of argument"
  echo "Usage: rem name"
  exit 1
fi

name=$1
matches=$(grep "$name" phonebook | wc -1)

if [ "$matches" -gt 1 ]
then
  echo "More than one match; please qualify further"
elif [ "$matches" -eq 1 ]; then
  grep -v "$name" phonebook > /temp/phonebook
  mv /temp/phonebook phonebook
else
  echo "can not find $name in the phone book"
fi

根据Unix习惯,程序成功运行不输出任何结构,出错时输出提示信息

case命令

case value in
pattern1) command
          command
          ;;
pattern2) command
          command;;
esac

类似于c++中的switch;;功能和break相同。
*可以匹配任何值,所以可以理解为switch中的default

if [ $# -ne 1 ]; then
  echo Usage: ctype char
  exit 1
fi

char=$1
case "$char" in
  [0-9])  echo digit;;
  [a-z])  echo lowercase letter;;
  [A-Z])  echo uppercase letter;;
  ?    )  echo special letter;;
  *    )  echo please type a single character;;
esac

pattern可以使用|运算符进行或运算。pattern1 | pattern2即表示只要符合两个模式中的任何一个即可

hour=$(date +%H)

case "$hour" in
  0? | 1[01] )  echo "good morning";;
  1[2-7]     )  echo "good afternoon";;
  *          )  echo "good evening";;
esac

使用-x进行调试

sh -x command

这种模式下,被执行了的命令都会直接被打印在shell中,变量也会被其值所替代显示出来。 所以可以方便地看出哪些命令被执行了,以及各变量的值是多少

空命令:

语法上需要使用命令的地方实际砂锅却不需要执行任何命令时可以使用空命令:来解决

&&||结构

command1 && command2

如果command1exit status为0,则command2才会被执行,否则不执行

command1 || command2

如果command1exit status不为0,则command2才会被执行,否则不执行

&&||结构都可以使用if结构改写