当前位置:   article > 正文

linux shell(中)

linux shell(中)

结构化命令

if语句

if-then

最基本的结构化命令是 if-then 语句。if-then 语句的格式如下:

if command
then
    commands
if

if command; then  # 通过把分号(;)放在待求值的命令尾部,可以将 then 语句写在同一行
    commands
if
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

bash shell 的 if 语句会运行 if 之后的命令。如果该命令的退出状态码(参见第 11 章)为 0(命令成功运行),那么位于 then 部分的命令就会被执行。如果该命令的退出状态码是其他值,则 then 部分的命令不会被执行,bash shell 会接着处理脚本中的下一条命令。fi 语句用来表示if-then 语句到此结束。

#!/bin/bash
# testing the if statement 
if pwd  # if 行中的 pwd 命令,由于退出状态码是 0,会执行if-then 内部的语句
then
    echo 'heheh'
if
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
#!/bin/bash
# testing an incorrect command
if IamNotCommand  # if 行中的 IamNotCommand 命令,由于命令不存在,不会执行if-then 内部的语句
then
    echo 'heheh'
if
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
if-then-else

if-then-else 语句在语句中提供了另外一组命令

if command
then
    commands
else
    commands
if
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
#!/bin/bash
# testing the else section
#
testuser=NoSuchUser
#
if grep $testuser /etc/passwd
then
    echo "The script files in the home directory of $testuser are:"
    ls /home/$testuser/*.sh
    echo
else
    echo "The user $testuser does not exist on this system."
    echo
fi
echo "We are outside the if statement"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

elif 语句行提供了另一个要测试的命令,这类似于原始的 if 语句行。

if command1
then            
    commands
elif command2
then
    more commands
fi    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
test命令

test 命令可以在 if-then 语句中测试不同的条件。如果 test 命令中列出的条件成立,那么test 命令就会退出并返回退出状态码 0。如果条件不成立,那么 test 命令就会退出并返回非 0 的状态码,这使得 if-then 语句不会再被执行。

test 命令的格式非常简单:

test condition
if test condition
then
    commands
fi
  • 1
  • 2
  • 3
  • 4
  • 5

如果不写 test 命令的 condition 部分,则它会以非 0 的退出状态码退出。

使用 test 命令确定变量中是否为空:

#!/bin/bash
# testing if a variable has content
#
my_variable="Full"
#
if test $my_variable  # my_variable不是空,返回状态0
then
    echo "The my_variable variable has content and returns a True."
    echo "The my_variable variable content is: $my_variable"
else
    echo "The my_variable variable doesn't have content,"
    echo "and returns a False."
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

bash shell 提供了另一种条件测试方式,无须在 if-then 语句中写明 test 命令:

if [ condition ]
then    
    commands
fi
  • 1
  • 2
  • 3
  • 4

方括号定义了测试条件。注意,第一个方括号之后和第二个方括号之前必须留有空格,否则就会报错。

test 命令和测试条件可以判断 3 类条件:

  • 数值比较(注意:不支持浮点数,只能用于整数)

  • 字符串比较

  • 文件比较

数值比较
比较描述
n1 -eq n2检查 n1 是否等于 n2
n1 -ge n2检查 n1 是否大于或等于 n2
n1 -gt n2检查 n1 是否大于 n2
n1 -le n2检查 n1 是否小于或等于 n2
n1 -lt n2检查 n1 是否小于 n2
n1 -ne n2检查 n1 是否不等于 n2
#!/bin/bash
# Using numeric test evaluations
#
value1=10
value2=11
#
if [ $value1 -gt 5 ]
then
    echo "The test value $value1 is greater than 5."
fi
#
if [ $value1 -eq $value2 ]
then
    echo "The values are equal."
else
    echo "The values are different."
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
字符串比较
比较描述
str1 = str2检查 str1 是否和 str2 相同
str1 > str2检查 str1 是否大于 str2
str1 < str2检查 str1 是否小于 str2
str1 != str2检查 str1 是否和 str2 不同
-n str1检查 str1 的长度是否不为 0
-z str1检查 str1 的长度是否为 0
#!/bin/bash
# Using string test evaluations
#
testuser=christine
#
if [ $testuser = christine ]
then
    echo "The testuser variable contains: christine"
else
    echo "The testuser variable contains: $testuser"
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
文件比较
比较描述
-d file检查 file 是否存在且为目录
-e file检查 file 是否存在
-f file检查 file 是否存在且为文件
-r file检查 file 是否存在且可读
-s file检查 file 是否存在且非空
-w file检查 file 是否存在且可写
-x file检查 file 是否存在且可执行
-O file检查 file 是否存在且属当前用户所有
-G file检查 file 是否存在且默认组与当前用户相同
file1 -nt file2检查 file1 是否比 file2 新
file1 -ot file2检查 file1 是否比 file2 旧
#!/bin/bash
# 检查目录
#
jump_directory=/home/Torfa
#
if [ -d $jump_directory ]
then
    echo "The $jump_directory directory exists."
    cd $jump_directory
    ls
else
    echo "The $jump_directory directory does NOT exist."
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
if-then的高级特性
  • 在子 shell 中执行命令的单括号

  • 用于数学表达式的双括号

  • 用于高级字符串处理功能的双方括号

单括号

单括号允许在 if 语句中使用子 shell。单括号形式的 test 命令格式如下:

(command)
  • 1

在 bash shell 执行 command 之前,会先创建一个子 shell,然后在其中执行命令。如果命令成功结束,则退出状态码会被设为 0,then 部分的命令就会被执行。

#!/bin/bash
# Testing a single parentheses condition
#
echo $BASH_SUBSHELL
#
if (echo $BASH_SUBSHELL)
then
    echo "The subshell command operated successfully."
#
else
    echo "The subshell command was NOT successful."
#
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

当脚本第一次(在 if 语句之前)执行 echo $BASH_SUBSHELL 命令时,是在当前 shell 中完成的。该命令会输出 0,表明没有使用子 shell($BASH_SUBSHELL :当前子 shell 环境的嵌套级别(初始值是 0))。在if 语句内,脚本在子 shell 中执行 echo $BASH_SUBSHELL 命令,该命令会输出 1,表明使用了子 shell。子 shell 操作成功结束,接下来是执行 then 部分的命令

双括号

双括号命令允许在比较过程中使用高级数学表达式。

符号描述
val++后增
val–后减
++val先增
–val先减
!逻辑求反
-位求反
**幂运算
<<左位移
>>右位移
&位布尔 AND
&&逻辑 AND
|逻辑OR
#!/bin/bash
# Testing a double parentheses command
#
val1=10
#
if (( $val1 ** 2 > 90 ))
then
    (( val2 = $val1 ** 2 ))
    echo "The square of $val1 is $val2,"
    echo "which is greater than 90."
#
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
双方括号

双方括号命令提供了针对字符串比较的高级特性。双方括号的格式如下:

[[ expression ]]
  • 1

expression 可以使用 test 命令中的标准字符串比较。除此之外,它还提供了 test 命令所不具备的另一个特性——模式匹配。

在进行模式匹配时,可以定义通配符或正则表达式

#!/bin/bash
# Using double brackets for pattern matching
#
#
if [[ $BASH_VERSION == 5.* ]]
then
    echo "You are using the Bash Shell version 5 series."
fi
# 上述脚本中使用了双等号(==)。双等号会将右侧的字符串(5.*)视为一个模式并应用模式匹配规则。
# 双方括号命令会对$BASH_VERSION 环境变量进行匹配,看是否以字符串 5.起始。
# 如果是,则测试通过,shell 会执行 then 部分的命令。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
Case命令

有了 case 命令,无须再写大量的 elif 语句来检查同一个变量的值了。case 命令会采用列表格式来检查变量的多个值:

case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
  • 1
  • 2
  • 3
  • 4
  • 5
#!/bin/bash
# Using a short case statement
#
case $USER in
rich | christine)
    echo "Welcome $USER"
    echo "Please enjoy your visit.";;
barbara | tim)
    echo "Hi there, $USER"
    echo "We're glad you could join us.";;
testing)
    echo "Please log out when done with test.";;
*)
    echo "Sorry, you are not allowed here."
esac
$
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

循环

for

bash shell 提供了 for 命令,以允许创建遍历一系列值的循环。每次迭代都使用其中一个值来执行已定义好的一组命令。for 命令的基本格式如下:

for var in list
do
    commands
done
  • 1
  • 2
  • 3
  • 4
#!/bin/bash
# basic for command 读取列表中的值
for test in Alabama Alaska Arizona Arkansas California Colorado
do
    echo The next state is $test
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

for 命令使用空格来划分列表中的每个值。如果某个值含有空格,则必须将其放入双引号内

#!/bin/bash
# an example of how to properly define values
for test in Nevada "New Hampshire" "New Mexico" "New York"
do
    echo "Now going to $test"
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
可以从变量中读取列表
#!/bin/bash
# using a variable to hold the list
list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut"
for state in $list # 
do
    echo "Have you ever visited $state?"
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

$list 变量包含了用于迭代的值列表。注意,脚本中还使用了另一个赋值语句向$list 变量包含的值列表中追加(或者说是拼接)了一项。这是向变量中已有的字符串尾部添加文本的一种常用方法。

从命令中读取值列表
#!/bin/bash
# reading values from a file
file="states.txt"
for state in $(cat $file)
do
    echo "Visit beautiful $state"
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用 cat 命令来输出文件 states.txt 的内容,states.txt 文件中每
个值各占一行,而不是以空格分隔。

更改字段分割符

IFS环境变量定义了 bash shell 用作字段分隔符的一系列字符。在默认情况下,bash shell 会将下列字
符视为字段分隔符:

  • 空格

  • 制表符

  • 换行符

如果 bash shell 在数据中看到了这些字符中的任意一个,那么它就会认为这是列表中的一个新字段的开始。

可以在 shell 脚本中临时更改 IFS 环境变量的值,指定字段分隔符的字符。

#!/bin/bash
# reading values from a file
file="states.txt"

IFS.OLD=$IFS
IFS=$'\n'  # 告诉 bash shell 忽略数据中的空格和制表符
for state in $(cat $file)
do
    echo "Visit beautiful $state"
done
IFS=$IFS.OLD # 恢复默认值,保证后续使用默认值的操作能正常运行


# IFS=:   # 如果要遍历文件中以冒号分隔的值,则只需将 IFS 的值设为冒号即可

# IFS=$'\n:;"'  # 将换行符、冒号、分号和双引号作为字段分隔符
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
使用通配符读取目录
#!/bin/bash
# iterate through all the files in a directory
for file in /home/rich/test/*
do
    if [ -d "$file" ]
    then
        echo "$file is a directory"
    elif [ -f "$file" ]
    then
        echo "$file is a file"
    fi
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
#!/bin/bash
# 可以在 for 命令中列出多个目录通配符
for file in /home/rich/.b* /home/rich/badtest
do
    if [ -d "$file" ]
    then
        echo "$file is a directory"
    elif [ -f "$file" ]
    then
        echo "$file is a file"
    else
        echo "$file doesn't exist"
    fi
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
C 语言风格的 for 命令

bash 中仿 C 语言的 for 循环的基本格式如下:

for (( variable assignment ; condition ; iteration process ))

# demo
for (( a = 1; a < 10; a++ ))
  • 1
  • 2
  • 3
  • 4

注意,有些地方与 bash shell 标准的 for 命令并不一致:

  • 变量赋值可以有空格

  • 迭代条件中的变量不以美元符号开头

  • 迭代过程的算式不使用 expr 命令格式

#!/bin/bash
# testing the C-style for loop

for (( i=1; i <= 10; i++ ))
do
    echo "The next number is $i"
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

仿 C 语言的 for 命令也允许为迭代使用多个变量

#!/bin/bash
# multiple variables
for (( a=1, b=10; a <= 10; a++, b-- ))
do
    echo "$a - $b"
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
while

while 命令在某种程度上糅合了 if-then 语句和 for 循环。while 命令的格式如下:

while test command
do
    other commands
done
  • 1
  • 2
  • 3
  • 4

while 命令中定义的 test command 与 if-then 语句中的格式一模一样。可以使用任何 bash shell 命令,或者用 test command 进行条件测试。

while 命令的关键在于所指定的 test command 的退出状态码必须随着循环中执行的命令而改变。如果退出状态码不发生变化,那 while 循环就成了死循环。

#!/bin/bash
# while command test
var1=10
while [ $var1 -gt 0 ]
do
    echo $var1
    var1=$[ $var1 - 1 ]
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

while 命令允许在 while 语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用于决定是否结束循环

#!/bin/bash
# testing a multicommand while loop
var1=10
while echo $var1
        [ $var1 -ge 0 ]
do
    echo "This is inside the loop"
    var1=$[ $var1 - 1 ]
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
until

与 while 命令工作的方式完全相反,until 命令要求指定一个返回非 0 退出状态码的测试命令。只要测试命令的退出状态码不为 0,bash shell 就会执行循环中列出的命令。一旦测试命令返回了退出状态码 0,循环就结束了。

until test command
do
    other commands
done
  • 1
  • 2
  • 3
  • 4
循环控制
breadk

break 命令是退出循环的一种简单方法。你可以用 break 命令退出任意类型的循环,包括while 循环和 until 循环。

#!/bin/bash
# breaking out of a for loop
for var1 in 1 2 3 4 5 6 7 8 9 10
do
    if [ $var1 -eq 5 ]
    then
        break
    fi
    echo "Iteration number: $var1"
done
echo "The for loop is completed"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在处理多个循环时,break 命令会自动结束你所在的最内层循环:

#!/bin/bash
# breaking out of an inner loop
for (( a = 1; a < 4; a++ ))
do
    echo "Outer loop: $a"
    for (( b = 1; b < 100; b++ ))
    do
        if [ $b -eq 5 ]
        then
            break  # 结束内层循环
        fi
        echo " Inner loop: $b"
    done
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

有时你位于内层循环,但需要结束外层循环。break 命令接受单个命令行参数:

break n
  • 1

其中 n 指定了要跳出的循环层级。在默认情况下,n 为 1,表明跳出的是当前循环。如果将 n 设为 2,那么 break 命令就会停止下一级的外层循环:

#!/bin/bash
# breaking out of an outer loop
for (( a = 1; a < 4; a++ ))
do
    echo "Outer loop: $a"
    for (( b = 1; b < 100; b++ ))
    do
        if [ $b -gt 4 ]
        then
            break 2 # 结束外层循环
        fi
        echo " Inner loop: $b"
    done
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
continue

continue 命令可以提前中止某次循环,但不会结束整个循环。你可以在循环内部设置 shell不执行命令的条件。

#!/bin/bash
# using the continue command
for (( var1 = 1; var1 < 15; var1++ ))
do
    if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
    then
        continue
    fi
    echo "Iteration number: $var1"
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

也可以在 while 循环和 until 循环中使用 continue 命令,但要特别小心。记住,当 shell执行 continue 命令时,它会跳过剩余的命令

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号