Skip to content

Latest commit

 

History

History
389 lines (303 loc) · 9.93 KB

06.Shell语句.md

File metadata and controls

389 lines (303 loc) · 9.93 KB

Shell 语句

if 语句

if 是条件语句,elif 是条件分支,else 是不成立的情况;then 是执行语句

if commands; then
  commands
[elif commands; then
  commands...]
[else
  commands]
fi
# 如果 then 不和 if 写在同一行,可以不用 ;
if true 
then 
  echo 'hello world'
fi

if 后可以跟命令,如果命令成功(返回 0),则执行 then 中的语句

if echo 'hi'; then echo 'hello world'; fi
# hi
# hello world

if 后面也可以跟任意多的命令,所有命令都会执行,但是只有最后一个命令用于判断真伪(如果返回 0,就会执行 then 之后的内容)

if false; true; then echo 'hello world'; fi
#hello world

test

if 结构的判断条件一般使用 test 命令,test命令执行成功返回 0,失败返回 1

# one
test expressions

# two
[ exporessions ]

# three(只有此写法支持正则)
[[ expressions ]]
  • 注意⚠️:建议使用 [[]],这允许更复杂的表达式

文件判断

  • [[ -b file ]]:如果 file 存在并且是一个块(设备)文件,为 true。
  • [[ -c file ]]:如果 file 存在并且是一个字符(设备)文件,为 true。
  • [[ -d file ]]:如果 file 存在并且是一个目录,为 true。
  • [[ -e file ]]:如果 file 存在,为 true。(不建议使用 -a
  • [[ -f file ]]:如果 file 存在并且是一个普通文件,为 true。
  • [[ -g file ]]:如果 file 存在并且设置了组 ID,为 true。
  • [[ -G file ]]:如果 file 存在并且属于有效的组 ID,为 true。
  • [[ -h file ]]:如果 file 存在并且是符号链接,为 true。
  • [[ -k file ]]:如果 file 存在并且设置了它的“sticky bit”,为 true。
  • [[ -L file ]]:如果 file 存在并且是一个符号链接,为 true。
  • [[ -N file ]]:如果 file 存在并且自上次读取后已被修改,为 true。
  • [[ -O file ]]:如果 file 存在并且属于有效的用户 ID,为 true。
  • [[ -p file ]]:如果 file 存在并且是一个命名管道,为 true。
  • [[ -r file ]]:如果 file 存在并且可读(当前用户有可读权限),为 true。
  • [[ -s file ]]:如果 file 存在且其长度大于零,为 true。
  • [[ -S file ]]:如果 file 存在且是一个网络 socket,为 true。
  • [[ -t fd ]]:如果 fd 是一个文件描述符,并且重定向到终端,为 true。这可以用来判断是否重定向了标准输入/输出/错误。
  • [[ -u file ]]:如果 file 存在并且设置了 setuid 位,为 true。
  • [[ -w file ]]:如果 file 存在并且可写(当前用户拥有可写权限),为 true。
  • [[ -x file ]]:如果 file 存在并且可执行(有效用户有执行/搜索权限),为 true。
  • [[ FILE1 -nt FILE2 ]]:如果 FILE1 比 FILE2 的更新时间更近,或者 FILE1 存在而 FILE2 不存在,为 true。
  • [[ FILE1 -ot FILE2 ]]:如果 FILE1 比 FILE2 的更新时间更旧,或者 FILE2 存在而 FILE1 不存在,为 true。
  • [[ FILE1 -ef FILE2 ]]:如果 FILE1 和 FILE2 引用相同的设备和 inode 编号,为 true。

字符串判断

  • [ string ]:如果string不为空(长度大于0),为 true。
  • [ -n string ]:如果字符串string的长度大于零,为 true。
  • [ -z string ]:如果字符串string的长度为零,为 true。
  • [ string1 = string2 ]:如果string1和string2相同,为 true。
  • [ string1 == string2 ]: 等同于[ string1 = string2 ]。
  • [ string1 != string2 ]:如果string1和string2不相同,为 true。
  • [ string1 '>' string2 ]:如果按照字典顺序string1排列在string2之后,为 true
  • [ string1 '<' string2 ]:如果按照字典顺序string1排列在string2之前,为 true

注意:如果是 test 命令内部的 <>,则需要使用 '' 包裹或 \ 转义

整数判断

  • [ integer1 -eq integer2 ]:如果相等,则为 true。
  • [ integer1 -ne integer2 ]:如果不等,则为 true。
  • [ integer1 -le integer2 ]:如果integer1 <= integer2,则为 true。
  • [ integer1 -lt integer2 ]:如果integer1 < integer2,则为 true。
  • [ integer1 -ge integer2 ]:如果integer1 >= integer2,则为 true。
  • [ integer1 -gt integer2 ]:如果integer1 > integer2,则为 true。

正则判断

[[ string1 =~ regex ]]
#!/bin/bash

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
  echo "INT is an integer."
  exit 0
else
  echo "INT is not an integer." >&2
  exit 1
fi

逻辑运算

&&: 也可使用参数 -a||: 也可使用参数 -o!: 取反。

注意:使用 ! 最好使用 ()

if [[ ! \( $INT -ge $MIN_VAL -a $INT -le $MAX_VAL \) ]]; then
    echo "$INT is outside $MIN_VAL to $MAX_VAL."
else
    echo "$INT is in range."
fi

利用逻辑运算搭配普通的命令,进行运算

# 一般情况,只有第一个成功后才可以进入第二个命令
mkdir temp && cd temp
# 使用 test 命令
[ -d temp ] || mkdir temp
# 如果 temp 命令不存在,则终止
[ ! -d temp ] && exit 1

算术判断

使用 (()) 作为算术条件进行判断。算术判断不需要使用 test 命令,这个结构由返回值决定

  • 在算术表达式中,true 代表 1(成功条件,执行 then),false 代表 0
if ((3 > 2)); then
  echo "true"
fi

# 但是这种不属于算术判断
if [[ 3 -gt 2 ]]; then
  echo "true"
fi
  • 也可以使用变量赋值,下面的条件会先赋值,再判断;如果单独运行 (( foo = 5 )),那么会返回 5
if (( foo = 5 ));then echo "foo is $foo"; fi
#foo is 5

case 语句

如果条件判断中,有多个 if 或者 elif,可以使用 case

case expression in
  pattern )
    commands ;;
  pattern )
    commands ;;
  ...
esac

case 匹配中可以使用任意通配符

  • a):匹配a。
  • a|b):匹配a或b。
  • [[:alpha:]]):匹配单个字母。
  • ???):匹配3个字符的单词。
  • *.txt):匹配.txt结尾。
  • *):匹配任意输入,通过作为case结构的最后一个模式
#!/bin/bash

echo -n "输入一个字母或数字 > "
read character
case $character in
  [[:lower:]] | [[:upper:]] ) echo "输入了字母 $character"
                              ;;
  [0-9] )                     echo "输入了数字 $character"
                              ;;
  * )                         echo "输入不符合要求"
esac

Bash 4.0之后,允许匹配多个条件,这时可以用;;&终止每个条件块

#!/bin/bash
# test.sh

read -n 1 -p "Type a character > "
echo
case $REPLY in
  [[:upper:]])    echo "'$REPLY' is upper case." ;;&
  [[:lower:]])    echo "'$REPLY' is lower case." ;;&
  [[:alpha:]])    echo "'$REPLY' is alphabetic." ;;&
  [[:digit:]])    echo "'$REPLY' is a digit." ;;&
  [[:graph:]])    echo "'$REPLY' is a visible character." ;;&
  [[:punct:]])    echo "'$REPLY' is a punctuation symbol." ;;&
  [[:space:]])    echo "'$REPLY' is a whitespace character." ;;&
  [[:xdigit:]])   echo "'$REPLY' is a hexadecimal digit." ;;&
esac

while 循环

while condition; do
  commands
done
  • while 循环中也可以使用 test 命令
number=0
while [ "$number" -lt 10 ]; do
  echo "Number = $number"
  number=$((number + 1))
done

until 循环

until 循环与 while 循环相反,只要不符合条件,就继续执行括号中的内容

until condition
do
  commands
done
until false; do echo 'Hi, until looping ...'; done

for ... in

for...in 循环用于遍历列表的每一项

for variable in list
do
  commands
done
  • 列表可以由通配符产生,也可以由子命令产生
for i in *.png; do
  ls -l $i
done
####
count=0
for i in $(cat ~/.bash_profile); do
  count=$((count + 1))
  echo "Word $count ($i) contains $(echo -n $i | wc -c) characters"
done
  • in list 的部分可以省略,这时 list 默认等于脚本的所有参数 $@
for filename; do
  echo "$filename"
done

# 等同于

for filename in "$@" ; do
  echo "$filename"
done

for 循环

for (( expression1; expression2; expression3 )); do
  commands
done
for (( i=0; i<5; i=i+1 )); do
  echo $i
done

break、continue

Bash 提供了两个内部命令 breakcontinue,用来在循环内部跳出循环。

select 结构

select 结构主要用来生成简单的菜单。它的语法与 for...in 循环基本一致。

select name
[in list]
do
  commands
done

Bash 会对select依次进行下面的处理。

select 生成一个菜单,内容是列表 list 的每一项,并且每一项前面还有一个数字编号。

  1. Bash 提示用户选择一项,输入它的编号。
  2. 用户输入以后,Bash 会将该项的内容存在变量name,该项的编号存入环境变量REPLY。如果用户没有输入,就按回车键,Bash 会重新输出菜单,让用户选择。
  3. 执行命令体commands。
  4. 执行结束后,回到第一步,重复这个过程。
#!/bin/bash
# select.sh

select brand in Samsung Sony iphone symphony Walton
do
  echo "You have chosen $brand"
done

执行上面的脚本,Bash 会输出一个品牌的列表,让用户选择。

$ ./select.sh
# 1) Samsung
# 2) Sony
# 3) iphone
# 4) symphony
# 5) Walton
#?

如果用户没有输入编号,直接按回车键。Bash 就会重新输出一遍这个菜单,直到用户按下Ctrl + c,退出执行。

select 可以与 case 结合,针对不同项,执行不同的命令。

#!/bin/bash

echo "Which Operating System do you like?"

select os in Ubuntu LinuxMint Windows8 Windows10 WindowsXP
do
  case $os in
    "Ubuntu"|"LinuxMint")
      echo "I also use $os."
    ;;
    "Windows8" | "Windows10" | "WindowsXP")
      echo "Why don't you try Linux?"
    ;;
    *)
      echo "Invalid entry."
      break
    ;;
  esac
done

上面例子中,case针对用户选择的不同项,执行不同的命令。