#!/bin/bash # testing multiple commands in the then section testuser=Christine if grep $testuser /etc/passwd then echo "This is my first command" echo "This is my second command" echo "I can even put in other commands besides echo:" ls -a /home/$testuser/.b* # 显示以b开头的所有文件 fi
$ ./test3.sh Christine:x:501:501:Christine B:/home/Christine:/bin/bash This is my first command This is my second command I can even put in other commands besides echo: /home/Christine/.bash_history /home/Christine/.bash_profile /home/Christine/.bash_logout /home/Christine/.bashrc
2.2 if-then-else语句
语法格式:
1 2 3 4 5 6
if command then commands else commands fi
示例
1 2 3 4 5 6 7 8 9 10 11 12
#!/bin/bash # testing the else section testuser=NoSuchUser if grep $testuser /etc/passwd then echo "The bash files for user $testuser are:" ls -a /home/$testuser/.b* echo else echo "The user $testuser does not exist on this system." echo fi
执行结果:
1 2 3 4
$ ./test4.sh The user NoSuchUser does not exist on this system. $
2.3 elif语句
语法格式:
1 2 3 4 5 6 7
if command1 then commands elif command2 then more commands fi
示例
1 2 3 4 5 6 7 8 9 10 11
#!/bin/bash # Testing nested ifs - use elif testuser=NoSuchUser if grep $testuser /etc/passwd then echo "The user $testuser exists on this system." elif ls -d /home/$testuser then echo "The user $testuser does not exist on this system." echo "However, $testuser has a directory." fi
执行结果:
1 2 3
/home/NoSuchUser The user NoSuchUser does not exist on this system. However, NoSuchUser has a directory.
#!/bin/bash # Using numeric test evaluations value1=10 value2=11 if [ $value1 -gt 5 ] # 或者 if test $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
2.4.2 字符串比较
2.4.3 文件比较
2.5 复合条件测试
if-then语句可以使用布尔逻辑来组合测试。有两种布尔运算符可用:
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
示例
1 2 3 4 5 6 7 8 9
#!/bin/bash # testing compound comparisons
if [ -d $HOME ] && [ -w $HOME/testing ] then echo "The file exists and you can write to it" else echo "I cannot write to the file" fi
#!/bin/bash # using the casecommand # case $USER in rich | barbara) echo "Welcome, $USER" echo "Please enjoy your visit";; testing) echo "Special testing account";; jessica) echo "Do not forget to log off when you're done";; *) echo "Sorry, you are not allowed here";; esac
执行结果:
1 2 3
$ ./test26.sh Welcome, rich Please enjoy your visit
3 循环结构化命令
3.1 for命令
语法格式:
1 2 3 4
for var in list do commands done
3.1.1 读取列表中的值
for命令最基本的用法就是遍历for命令自身所定义的一系列值。
示例
1 2 3 4 5 6
#!/bin/bash # basic forcommand for test in Alabama Alaska Arizona Arkansas California Colorado do echo The next state is $test done
执行结果:
1 2 3 4 5 6 7
$ ./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
#!/bin/bash # using a variable to hold the list list="Alabama Alaska Arizona Arkansas Colorado" list=$list" Connecticut" # 向$list变量包含的已有列表中添加(或者说是拼接)了一个值。这是向变量中存储的已有文本字符串尾部添加文本的一个常用方法,例如:PATH=$PATH:/home/uusama/mysql/bin for state in $list do echo "Have you ever visited $state?" done
执行结果:
1 2 3 4 5 6 7
$ ./test4 Have you ever visited Alabama? Have you ever visited Alaska? Have you ever visited Arizona? Have you ever visited Arkansas? Have you ever visited Colorado? Have you ever visited Connecticut?
#!/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
$ ./test11 10 This is inside the loop 9 This is inside the loop 8 This is inside the loop 7 This is inside the loop 6 This is inside the loop 5 This is inside the loop 4 This is inside the loop 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
#!/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
$ ./test17 Iteration number: 1 Iteration number: 2 Iteration number: 3 Iteration number: 4 The for loop is completed
② 跳出内部循环
在处理多个循环时,break命令会自动终止你所在的最内层的循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#!/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
#!/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
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
3.8 实例:查找可执行文件
扫描PATH环境变量中所有的目录中的可执行文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#!/bin/bash # finding files in the PATH IFS=: for folder in $PATH do echo "$folder:" for file in $folder/* do if [ -x $file ] # 是否是可执行文件 then echo " $file" fi done done
#!/bin/bash # using one command line parameter # 计算阶乘 factorial=1 for (( number=1; number <= $1 ; number++ )) do factorial=$[ $factorial * $number ] done echo The factorial of $1 is $factorial
执行结果:
1 2
$ ./test1.sh 5 The factorial of 5 is 120
1 2 3 4 5 6 7
#!/bin/bash # testing two command line parameters # total=$[ $1 * $2 ] echo The first parameter is $1. echo The second parameter is $2. echo The total value is $total.
1 2 3 4
$ ./test2.sh 2 5 The first parameter is 2. The second parameter is 5. The total value is 10.
#!/bin/bash # testing parameters before use # if [ -n "$1" ] # 测试$1长度是否非零 then echo Hello $1, glad to meet you. else echo "Sorry, you did not identify yourself. " fi
1 2 3 4 5
$ ./test7.sh Rich Hello Rich, glad to meet you. $ $ ./test7.sh Sorry, you did not identify yourself.
4.2 特殊参数变量
4.2.1 参数统计
特殊变量$#含有脚本运行时携带的命令行参数的个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#!/bin/bash # Testing parameters # if [ $# -ne 2 ] # 检测参数数量是否为2 then echo echo Usage: test9.sh a b echo else total=$[ $1 + $2 ] echo echo The total is $total echo fi
1 2 3 4 5 6 7 8 9 10 11 12 13
$ $ bash test9.sh
Usage: test9.sh a b $ bash test9.sh 10
Usage: test9.sh a b $ bash test9.sh 10 15
The total is 25 $
此外${!#}返回最后一个参数的值,如果没有参数,则返回脚本名称。
1 2 3 4 5 6 7 8
#!/bin/bash # Grabbing the last parameter # params=$# echo echo The last parameter is $params echo The last parameter is ${!#} echo
1 2 3 4 5 6 7 8
$ bash test10.sh 1 2 3 4 5 The last parameter is 5 The last parameter is 5 $ $ bash test10.sh The last parameter is 0 The last parameter is test10.sh $
4.2.2 抓取所有的数据
$*和$@变量可以用来轻松访问所有的参数。这两个变量都能够在单个变量中存储所有的命令行参数。
$*变量会将这些参数视为一个整体,而不是多个个体
$@变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词
示例
1 2 3 4 5
#!/bin/bash # testing $* and $@ # echo "Using the \$* method: $*" echo "Using the \$@ method: $@"
1 2 3 4
$ ./test11.sh rich barbara katie jessica Using the $* method: rich barbara katie jessica Using the $@ method: rich barbara katie jessica $
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#!/bin/bash # testing $* and $@ count=1 for param in "$*" do echo "\$* Parameter #$count = $param" count=$[ $count + 1 ] done
count=1 for param in "$@" do echo "\$@ Parameter #$count = $param" count=$[ $count + 1 ] done
#!/bin/bash # extracting command line options as parameters # echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option" ;; -b) echo "Found the -b option" ;; -c) echo "Found the -c option" ;; *) echo "$1 is not an option" ;; esac shift done
1 2 3 4 5
$ ./test15.sh -a -b -c -d Found the -a option Found the -b option Found the -c option -d is not an option
# extracting options and parameters echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option" ;; -b) echo "Found the -b option";; -c) echo "Found the -c option" ;; --) shift break ;; # 选项列表结束,跳出循环,后面的为参数 *) echo "$1 is not an option";; esac shift done # count=1 for param in $@ do echo "Parameter #$count: $param" count=$[ $count + 1 ] done
1 2 3 4 5 6 7
$ ./test16.sh -c -a -b -- test1 test2 test3 Found the -c option Found the -a option Found the -b option Parameter #1: test1 Parameter #2: test2 Parameter #3: test3
#!/bin/bash # extracting command line options and values echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option";; -b) param="$2" echo "Found the -b option, with parameter value $param" shift ;; -c) echo "Found the -c option";; --) shift break ;; *) echo "$1 is not an option";; esac shift done # count=1 for param in "$@" do echo "Parameter #$count: $param" count=$[ $count + 1 ] done
1 2 3 4
$ ./test17.sh -a -b test1 -d Found the -a option Found the -b option, with parameter value test1 -d is not an option
#!/bin/bash # reading data from a file # count=1 cat test | while read line do echo "Line $count: $line" count=$[ $count + 1] done echo "Finished processing the file"
#!/bin/bash # ./test8 # testing STDERR messages echo "This is an error" >&2 echo "This is normal output"
1 2 3
$ ./test8 # 这样运行没什么区别 This is an error # 实际上输出到了STDERR上 This is normal output # STDOUT
但是:
1 2 3 4
$ ./test8 2>test9 This is normal output # 没有显示This is an error,因为它被重定向到了test9中 $ cat test9 This is an error
5.2.2 永久重定向
可以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。
1
exec fp>file
含义:将文件描述符fp重定向到文件file
示例
1 2 3 4 5 6
#!/bin/bash # redirecting all output to a file exec 1>testout echo "This is a test of redirecting all output" echo "from a script to another file." echo "without having to redirect every individual line"
#!/bin/bash # creating and using a temp file tempfile=$(mktemp test19.XXXXXX) # 命令替换,mktemp的输出是临时文件名 exec 3>$tempfile # 永久重定向 echo "This script writes to temp file $tempfile" # STDOUT echo "This is the first line" >&3 # 临时重定向 echo "This is the second line." >&3 echo "This is the last line." >&3 exec 3>&- # 关闭文件描述符 echo "Done creating temp file. The contents are:" cat $tempfile rm -f $tempfile 2> /dev/null
$ ./test19 # 注意打印顺序 This script writes to temp file test19.vCHoya Done creating temp file. The contents are: This is the first line This is the second line. This is the last line.
#!/bin/bash # creating a temp file in /tmp tempfile=$(mktemp -t tmp.XXXXXX) echo "This is a test file." > $tempfile echo "This is the second line of the test." >> $tempfile echo "The temp file is located at: $tempfile" cat $tempfile rm -f $tempfile
1 2 3 4
$ ./test20 The temp file is located at: /tmp/tmp.Ma3390 This is a test file. This is the second line of the test.
5.6.3 创建临时目录
-d选项告诉mktemp命令来创建一个临时目录而不是临时文件。返回目录名。
示例
1 2 3 4 5 6 7 8 9 10 11
#!/bin/bash # using a temporary directory tempdir=$(mktemp -d dir.XXXXXX) cd $tempdir tempfile1=$(mktemp temp.XXXXXX) tempfile2=$(mktemp temp.XXXXXX) exec 7>$tempfile1 exec 8>$tempfile2 echo "Sending data to directory $tempdir" echo "This is a test line of data for $tempfile1" >&7 echo "This is a test line of data for $tempfile2" >&8
#!/bin/bash # using the tee commandfor logging tempfile=test22file echo "This is the start of the test" | tee $tempfile echo "This is the second line of the test" | tee -a $tempfile # 追加 echo "This is the end of the test" | tee -a $tempfile # 追加
1 2 3 4 5 6 7 8
$ ./test22 This is the start of the test This is the second line of the test This is the end of the test $ cat test22file This is the start of the test This is the second line of the test This is the end of the test
#!/bin/bash # Testing signal trapping trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT echo This is a test script count=1 while [ $count -le 10 ] do echo "Loop #$count" sleep 1 count=$[ $count + 1 ] done echo "This is the end of the test script"
$ ./test1.sh This is a test script Loop #1 Loop #2 Loop #3 Loop #4 Loop #5 ^C Sorry! I have trapped Ctrl-C Loop #6 Loop #7 Loop #8 ^C Sorry! I have trapped Ctrl-C Loop #9 Loop #10 This is the end of the test script
$ ./test6.sh & [1] 3568 $ This is Test Script #1 $ ./test7.sh & [2] 3570 $ This is Test Script #2 $ ./test8.sh & [3] 3573 $ And...another Test script $ ./test9.sh & [4] 3576 $ Then...there was one more test script
#!/bin/bash # using a functionin a script function func1 { echo "This is an example of a function" } count=1 while [ $count -le 5 ] do func1 count=$[ $count + 1 ] done echo "This is the end of the loop" func1 # 使用函数 echo "Now this is the end of the script"
1 2 3 4 5 6 7 8 9
$ ./test1 This is an example of a function This is an example of a function This is an example of a function This is an example of a function This is an example of a function This is the end of the loop This is an example of a function Now this is the end of the script
#!/bin/bash # testing the exit status of a function func1() { echo "trying to display a non-existent file" ls -l badfile } echo "testing the function: " func1 echo "The exit status is: $?"
1 2 3 4 5
$ ./test4 testing the function: trying to display a non-existent file ls: badfile: No such file or directory The exit status is: 1
#!/bin/bash # using the returncommandin a function function dbl { read -p "Enter a value: " value echo "doubling the value" return $[ $value * 2 ] } dbl echo "The new value is $?"
#!/bin/bash # using the echo to return a value function dbl { read -p "Enter a value: " value echo $[ $value * 2 ] } result=$(dbl) echo "The new value is $result"
1 2 3 4 5 6
$ ./test5b Enter a value: 200 The new value is 400 $ ./test5b Enter a value: 1000 The new value is 2000
#!/bin/bash # trying to access script parameters inside a function function badfunc1 { echo $[ $1 * $2 ] } if [ $# -eq 2 ] then value=$(badfunc1) echo "The result is $value" else echo "Usage: badtest1 a b" fi
#!/bin/bash # trying to access script parameters inside a function function func7 { echo $[ $1 * $2 ] } if [ $# -eq 2 ] then value=$(func7 $1 $2) # 将命令行的参数作为函数参数 echo "The result is $value" else echo "Usage: badtest1 a b" fi
7.3.2 在函数中处理变量
暂略
7.4 数组变量
暂略
7.5 递归
暂略
7.6 创建库
bash shell允许创建函数库文件,然后在多个脚本中引用该库文件。
示例
有个叫作myfuncs的库文件,它定义了3个简单的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# my script functions function addem { echo $[ $1 + $2 ] } function multem { echo $[ $1 * $2 ] } function divem { if [ $2 -ne 0 ] then echo $[ $1 / $2 ] else echo -1 fi }