语法:
if command
then
commands
fi
或 通过把分号(;)放在待求值的命令尾部,可以将then语句写在同一行
if command; then
commands
fi
bash shell的if语句会运行if之后的命令。
如果该命令的 退出状态码为 0,那么位于then部分的命令就会被执行。
如果该命令的退出状态码是其他值,则 then部分的命令不会被执行,bash shell会接着处理脚本中的下一条命令。
fi语句用来表示if-then语句到此结束。
$ cat test1.sh
#!/bin/bash
# testing the if statement
if pwd
then
echo "it worked"
fi
$ ./test1.sh
/home/christine/scripts
It worked
2,if-then-else语句
提供了 commond 执行返回 非0退出状态码时 的处理逻辑.
if command
then
commands
else
commands
fi
3,elseif语句
if command1
then
commands
elif command2
then
more commands
fi
4,test命令
test condition
test命令 在bash shell中 可以 使用if-then语句测试退出状态码之外的条件.
test命令可以在if-then语句中测试不同的条件。如果test命令中列出的条件成立,那么test命令就会退出并返回退出状态码0。
test命令和测试条件可以判断3类条件。
·数值比较
·字符串比较
·文件比较
test 的 if-then语法:
if test condition
then
commands
fi
如果加入了条件,则test命令会测试该条件
如果不写test命令的 condition部分,则会以非0的退出状态码退出并执行else代码块语句.
可以使用test命令确定变量中是否为空.
if test $var
then
command
else
command
fi
bash shell提供了另一种条件测试方式,
第一个方括号之后和第二个方括号之前必须留有空格!!!
if [ condition ]
then
commands
fi
-n和-z可以很方便地用于检查一个变量是否为空:
非空 if [ -n "$string1" ]
为空 if [ -z "$string2" ]
!!! 未定义的变量长度也为 0;
4.3,文件比较
shell编程中 强大且用得最多的 比较形式。允许测试Linux文件系统中文件和目录的状态
表达式
描述
-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旧
4.3.1,检查目录
如果打算将文件写入目录或是准备切换到某个目录,那么先测试一下:
$ cat jump_point.sh
#!/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
$ ./jump_point.sh
The /home/Torfa directory does NOT exist.
4.3.2.检查对象是否存在
-e测试允许在使用文件或目录前先检查其是否存在:
$ cat update_file.sh
#!/bin/bash
location=$HOME
file_name="sentinel"
if [ -d $location ]
then
echo "OK on the $location directory"
echo "Now checking on the file, $file_name..."
if [ -e $location/$file_name ]
then
echo "OK on the file, $file_name."
echo "Updating file's contents."
date >> $location/$file_name
else
echo "File, $location/$file_name, does NOT exist."
echo "Nothing to update."
fi
else
echo "Directory, $location, does NOT exist."
echo "Nothing to update."
fi
$ ./update_file.sh
OK on the /home/christine directory
Now checking on the file, sentinel...
File, /home/christine/sentinel, does NOT exist.
Nothing to update.
$ touch /home/christine/sentinel
$ ./update_file.sh
OK on the /home/christine directory
Now checking on the file, sentinel...
OK on the file, sentinel.
Updating file's contents.
双方括号命令提供了针对字符串比较的高级特性。语法:
[[ expression ]]
expression可以使用 test命令中的标准字符串比较。还提供了 模式匹配。
双等号(==)会将右侧的字符串视为一个模式并应用模式匹配规则。
在进行模式匹配时,可以定义通配符或正则表达式(参见第20章)来匹配字符串
$ cat DoubleBrackets.sh
#!/bin/bash
if [[ $BASH_VERSION == 5.* ]]
then
echo "You are using the Bash Shell version 5 series."
fi
$ ./DoubleBrackets.sh
You are using the Bash Shell version 5 series.
重复多个命令直至达到某个特定条件.for命令允许创建遍历一系列值的循环。
语法:
for var in list
do
commands
done
或
for var in list; do
comands
done
8.1,读取列表中的值
遍历其自身所定义的一系列值
$ cat test1
#!/bin/bash
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo The next state is $test
done
$ ./test1
The next state is Alabama
The next state is Alaska
The next state is Arizona
The next state is Arkansas
The next state is California
The next state is Colorado
在最后一次迭代结束后,$test变量的值在shell脚本的剩余部分依然有效。它会一直保持最后一次迭代时的值(除非做了修改)!!!
8.2,读取列表中的复杂值
引号带来的复杂情况,shell看到 列表值中的单引号并尝试使用 它们 来定义一个单独的数据值.
$ cat badtest1
#!/bin/bash
for test in I don't know if this'll work
do
echo "word:$test"
done
$ ./badtest1
word:I
word:dont know if thisll
word:work
解决这个问题。
·使用转义字符(反斜线)将单引号转义。
·使用双引号来定义含有单引号的值。
#!/bin/bash
for test in I don\'t know if "this'll" work
do
echo "word:$test"
done
多单词值:for循环假定各个值之间是以空格分隔的,存在空格的单词,必须放入双引号内.
$ cat test3
#!/bin/bash
for test in Nevada "New Hampshire" "New Mexico" "New York"
do
echo "Now going to $test"
done
8.3,从变量中读取列表值
将一系列值集中保存在了一个变量中,然后需要遍历该变量中的整个值列表
$ cat test4
#!/bin/bash
list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut" ## 向$list变量包含的值列表中追加(拼接)了一项。这是向变量中已有的字符串尾部添加文本的一种常用方法。
for state in $list
do
echo "Have you ever visited $state?"
done
8.4,从命令中读取列表值
生成值列表的另一种途径是使用命令的输出。
$ cat test5
#!/bin/bash
file="states.txt" ##不包含路径的文件名赋给了变量。要求文件和脚本位于同一个目录中。否则则需要使用完整路径名(绝对/相对路径)来引用文件位置
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
$ cat states.txt
New York
New Hampshire
$ ./test5
Visit beautiful New
Visit beautiful York
Visit beautiful New
Visit beautiful Hampshire
文件中每个值各占一行,而不是以空格分隔。for命令仍然以每次一行的方式遍历cat命令的输出。
这并没有解决数据中含有空格的问题。如果列出了一个名字中有空格的值,则for命令仍然会用空格来分隔值。
8.5,更改字段分隔符
特殊的环境变量 IFS(internal field separator,内部字段分隔符)。
IFS环境变量定义了 bash shell 用作字段分隔符的一系列字符。在默认情况下,bash shell会将下列字符视为字段分隔符。
·空格
·制表符
·换行符
改 IFS的值,使其只能识别换行符:
IFS=$'\n'
该语句加入脚本,告诉bash shell忽略数据中的空格和制表符:
$ cat test5b
#!/bin/bash
file="states.txt"
IFS=$'\n'
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
$ ./test5b
Visit beautiful New York
Visit beautiful New Hampshire
安全的做法是在修改IFS之前保存原来的IFS值,之后再恢复它!!!
IFS.OLD=$IFS
IFS=$'\n'
... ...
IFS=$IFS.OLD
指定多个IFS字符,在赋值语句中将这些字符写在一起.
该语句会将换行符、冒号、分号和双引号作为字段分隔符:
IFS=$'\n:;"'
8.6,使用通配读取目录
可以用 for命令来自动遍历目录中的文件。
必须在文件名或路径名中使用通配符,会强制 shell 使用文件名通配符匹配(file globbing)。
文件名通配符匹配是 生成与指定通配符匹配的文件名或路径名 的过程。
$ cat test6
#!/bin/bash
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
$ ./test6
/home/rich/test/dir1 is a directory
/home/rich/test/myprog.c is a file
在 Linux中,目录名和文件名中包含空格是合法的。若目录名存在空格,应该将$file变量放入双引号内。
if [ -d "$file" ]
在test命令中,bash shell会将额外的单词视为参数,引发错误。
可以在for命令中列出多个目录通配符:
#!/bin/bash
for file in /home/rich/.b* /home/rich/badtest
do
....
done
C语言中的for命令包含循环变量初始化、循环条件以及每次迭代时修改变量的方法
当指定的条件不成立时,for循环就会停止。迭代条件使用标准的数学符号定义。
for (i = 0; i < 10; i++)
{
printf("The next number is %d\n", i);
}
bash中 仿C语言的for循环 的基本格式:
for (( variable assignment ; condition ; iteration process ))
仿C语言的for循环的格式使用了C语言风格而不是shell风格的变量引用方式:
for (( a = 1; a < 10; a++ ))
与bash shell标准的for命令并不一致: !!!!
·变量赋值可以有空格
·迭代条件中的变量不以美元符号开头
·迭代过程的算式不使用expr命令格式
示例:
$ cat test8
#!/bin/bash
for (( i=1; i <= 3; i++ ))
do
echo "The next number is $i"
done
$ ./test8
The next number is 1
The next number is 2
The next number is 3
语法:
while test command
do
other commands
done
如果退出状态码不发生变化,那while循环就成了死循环。
$ cat test10
#!/bin/bash
var1=3
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1 - 1 ]
done
$ ./test10
3
2
1
10.2,使用多个测试命令
while命令允许在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用于决定是否结束循环。
$ cat test11
#!/bin/bash
var1=3
while echo $var1
[ $var1 -ge 0 ]
do
echo "This is inside the loop"
var1=$[ $var1 - 1 ]
done
$ ./test11
3
This is inside the loop
2
This is inside the loop
1
This is inside the loop
0
This is inside the loop
-1
11,until命令 返回码非0循环
until命令要求指定一个返回非0退出状态码的测试命令.与while命令工作的方式相反.
格式:
until test commands
do
other commands
done
示例:
$ cat test12
#!/bin/bash
var1=100
until [ $var1 -eq 0 ]
do
echo $var1
var1=$[ $var1 - 25 ]
done
$ ./test12
100
75
50
25
12,嵌套循环
循环语句可以在循环内使用任意类型的命令包括其他循环命令.
13,循环处理文件数据
修改IFS环境变量,能强制for命令将文件中的每一行都作为单独的条目来处理,即便数据中有空格也是如此。
从文件中提取出单独的行后,可能还得使用循环来提取行中的数据。
处理/etc/passwd文件。这要求你逐行遍历该文件,将IFS变量的值改成冒号,以便分隔开每行中的各个字段:
$ cat test8
#!/bin/bash
IFS.OLD=$IFS
IFS=$'\n'
for entry in $(cat /etc/passwd)
do
echo "Values in $entry -"
IFS=:
for value in $entry
do
echo " $value"
done
done
IFS=$IFS.OLD
$ ./test8
Values in rich:x:501:501:Rich Blum:/home/rich:/bin/bash -
rich
x
501
501
Rich Blum
/home/rich
/bin/bash
Values in katie:x:502:502:Katie Blum:/home/katie:/bin/bash -
katie
x
502
502
Katie Blum
/home/katie
/bin/bash
shell在执行break命令时会尝试跳出当前正在执行的循环:
$ cat test17
#!/bin/bash
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"
$ ./test17
Iteration number: 1
Iteration number: 2
Iteration number: 3
Iteration number: 4
The for loop is completed
2,跳出内存循环
默认跳出内层循环
3,跳出外层循环
位于内层循环,需要结束外层循环。break命令接受单个命令行参数
break n
默认情况下,n为1,表明跳出的是当前循环。如果将n设为2,那么break命令就会停止下一级的外层循环;
$ cat test20
#!/bin/bash
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
$ ./test20
Outer loop: 1
Inner loop: 1
Inner loop: 2
Inner loop: 3
Inner loop: 4
14.2,continue命令
continue命令可以提前中止某次循环,但不会结束整个循环;
continue命令 也允许通过命令行参数指定要继续执行哪一级循环,n定义了要继续的循环层级:
continue n
15,处理循环输出 >
可以对循环的输出使用管道或进行重定向。这可以通过在done命令之后添加一个 > 处理命令来实现:
for file in /home/rich/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif
echo "$file is a file"
fi
done > output.txt
shell会将for命令的结果重定向至文件output.txt,而不再显示在屏幕上。!!!!
同样适用于将循环的结果传输到另一个命令:
$ cat test24
#!/bin/bash
for state in "North Dakota" Connecticut Illinois Alabama Tennessee
do
echo "$state is the next place to go"
done | sort
echo "This completes our travels"
$ ./test24
Alabama is the next place to go
Connecticut is the next place to go
Illinois is the next place to go
North Dakota is the next place to go
Tennessee is the next place to go
This completes our travels