本文的主要内容:
1、编写Shell脚本的一般步骤
2、在Shell脚本中输出文本
3、Shell脚本中的变量
4、Shell脚本中的函数
5、流程控制:if 分支结构
6、Shell中读取键盘输入
#!/bin/bash
# This is our first script.
echo 'Hello World!'
chmod 700 hello_world
./hello_world
例如:echo "a string"
格式如下:
command << tokentexttoken
这里的 command 是一个可以接受标准输入的命令名,token 是一个用来指示嵌入文本结束的字符串
把操作符"<<"改为 "<<-",shell 会忽略开头的 tab 字符,可使用缩进提高可读性
例如:
cat << _EOF_ a string _EOF_
或
cat <<- _EOF_ a string _EOF_
#!/bin/bash # Script to retrieve a file via FTP FTP_SERVER=*** FTP_PATH=*** REMOTE_FILE=*** ftp -n << _EOF_ open $FTP_SERVER user anonymous me@linuxbox cd $FTP_PATH hash get $REMOTE_FILE bye _EOF_ ls -l $REMOTE_FILE
variable=value(注:等号左右不能有空格)
a=5 b="a string"
$variable 或 ${variable}
b="a string" c="a string and $b" mv $filename ${filename}1
function name {
commands
return
}
或
name () {
commands
return
}
*例如#!/bin/bash function_1 () { echo "Function_1 executed." return } cat << _EOF_ $(function_1) _EOF_
*例如
funct_1 () { local foo #funct_1中的局部变量 foo=1 echo "funct_1: foo = $foo" }
if commands; thencommands[elif commands; thencommands...][elsecommands]fi
*例如:x=5 if [ $x = 5 ]; then echo "x equals 5." else echo "x does not equal 5." fi
当命令执行完毕后会给系统发送一个值,叫做退出状态。Shell 提供了一个参数$?可用来检查退出状态
例如:(状态0为命令执行成功)
$ ls -d /usr/bin/usr/bin$ echo $?0
*经常与 if 一块使用的命令是 test。test 命令执行各种各样的检查与比较,它有两种等价模式:
test expression或[ expression ]
*其中expression 为一个表达式,其执行结果是 true 或者是 false。当表达式为真时,这个 test 命令返回一个0退出状态,当表达式为假时,test 命令退出状态为1
*文件表达式
file1 -ef file2:file1 和 file2 拥有相同的索引号(通过硬链接两个文件名指向相同的文件)file1 -nt file2:file1新于 file2file1 -ot file2:file1早于 file2-b file:file 存在并且是一个块(设备)文件-c file:file 存在并且是一个字符(设备)文件-d file:file 存在并且是一个目录-e file:file 存在-f file:file 存在并且是一个普通文件-g file:file 存在并且设置了组 ID-G file:file 存在并且由有效组 ID 拥有-k file:file 存在并且设置了它的“sticky bit”-L file:file 存在并且是一个符号链接-O file:file 存在并且由有效用户 ID 拥有-p file:file 存在并且是一个命名管道-r file:file 存在并且可读(有效用户有可读权限)-s file:file 存在且其长度大于零-S file:file 存在且是一个网络 socket-t fd:fd 是一个定向到终端/从终端定向的文件描述符 。 这可以被用来决定是否重定向了标准输入/输出错误-u file:file 存在并且设置了 setuid 位-w file:file 存在并且可写(有效用户拥有可写权限)-x file:file 存在并且可执行(有效用户有执行/搜索权限)
*文件表达式例子(其中在表达式中参数$FILE两边的引号并不是必需的,但这可防范空参数)test_file () { # test-file: Evaluate the status of a file FILE=~/.bashrc if [ -e "$FILE" ]; then if [ -f "$FILE" ]; then echo "$FILE is a regular file." fi if [ -d "$FILE" ]; then echo "$FILE is a directory." fi if [ -r "$FILE" ]; then echo "$FILE is readable." fi if [ -w "$FILE" ]; then echo "$FILE is writable." fi if [ -x "$FILE" ]; then echo "$FILE is executable/searchable." fi else echo "$FILE does not exist" return 1 fi }
*字符串表达式
string:string 不为 null-n string:字符串 string 的长度大于零-z string:字符串 string 的长度为零string1 = string2或string1 == string2:string1 和 string2 相同. 单或双等号都可以,不过双等号更受欢迎string1 != string2:string1 和 string2 不相同string1 > string2:sting1 排列在 string2 之后string1 < string2:string1 排列在 string2 之前
注:> 和 <表达式操作符必须用引号引起来或者是用反斜杠转义,否则会被 shell 解释为重定向操作符,造成潜在地破坏结果
*字符串表达式例子:
#!/bin/bash # test-string: evaluate the value of a string ANSWER=maybe if [ -z "$ANSWER" ]; then echo "There is no answer." >&2 exit 1 fi if [ "$ANSWER" = "yes" ]; then echo "The answer is YES." elif [ "$ANSWER" = "no" ]; then echo "The answer is NO." elif [ "$ANSWER" = "maybe" ]; then echo "The answer is MAYBE." else echo "The answer is UNKNOWN." fi
*整型表达式
integer1 -eq integer2:integer1 等于 integer2integer1 -ne integer2:integer1 不等于 integer2integer1 -le integer2:integer1 小于或等于 integer2integer1 -lt integer2:integer1 小于 integer2integer1 -ge integer2:integer1 大于或等于 integer2integer1 -gt integer2:integer1 大于 integer2
*整型表达式例子:
#!/bin/bash # test-integer: evaluate the value of an integer. INT=-5 if [ -z "$INT" ]; then echo "INT is empty." >&2 exit 1 fi if [ $INT -eq 0 ]; then echo "INT is zero." else if [ $INT -lt 0 ]; then echo "INT is negative." else echo "INT is positive." fi if [ $((INT % 2)) -eq 0 ]; then echo "INT is even." else echo "INT is odd." fi fi
*目前的 bash 版本包含一个复合命令:[[ expression ]],与test相比增加了一个重要的新的字符串表达式:string1 =~ regex,若string1匹配扩展的正则表达式 regex则返回真
例子:
#!/bin/bash # test-integer2: evaluate the value of an integer. INT=-5 if [[ "$INT" =~ ^-?[0-9]+$ ]]; then if [ $INT -eq 0 ]; then echo "INT is zero." else if [ $INT -lt 0 ]; then echo "INT is negative." else echo "INT is positive." fi if [ $((INT % 2)) -eq 0 ]; then echo "INT is even." else echo "INT is odd." fi fi else echo "INT is not an integer." >&2 exit 1 fi
*为整数设计的复合命令:(( ))
例子:
#!/bin/bash # test-integer2a: evaluate the value of an integer. INT=-5 if [[ "$INT" =~ ^-?[0-9]+$ ]]; then if ((INT == 0)); then echo "INT is zero." else if ((INT < 0)); then echo "INT is negative." else echo "INT is positive." fi if (( ((INT % 2)) == 0)); then echo "INT is even." else echo "INT is odd." fi fi else echo "INT is not an integer." >&2 exit 1 fi
操作符 测 试 [[ ]] 和 (( )) AND -a && OR -o || NOT ! !
*bash 支持两种可以执行分支任务的控制操作符。这个 &&(AND)和||(OR)操作符作用如同复合命令[[ ]]中的逻辑操作符
*语法:command1 && command2 和 command1 || command2
*对于 && 操作符,只有当command1 执行成功后,才会执行 command2。对于 || 操作符,只有当command1 执行失败后, 才会执行command2
*例如:
$ mkdir temp && cd temp :在成功创建目录temp后跳转到temp$ [ -d temp ] || mkdir temp :若目录 temp 不存在则创建这个目录[ -d temp ] || exit 1 : 若目录temp不存在则返回退出状态1
*语法形式:read [-options] [variable...]
*读取一个整数:
echo -n "Please enter an integer -> " read var echo "var = '$var'"
*给多个变量赋值:
echo -n "Enter one or more values > " read var1 var2 echo "var1 = '$var1'" echo "var2 = '$var2'"
*若没有提供变量名,shell 变量 REPLY 会包含数据行
echo -n "Enter one or more values > " read echo "REPLY = '$REPLY'"
*read选项
-a array:把输入赋值到数组 array 中,从索引号零开始-d delimiter:用字符串 delimiter 中的第一个字符指示输入结束,而不是一个换行符-e:使用 Readline 来处理输入。这使得与命令行相同的方式编辑输入-n num:读取 num 个输入字符,而不是整行-p prompt :为输入显示提示信息,使用字符串 prompt
-r:Raw mode. 不把反斜杠字符解释为转义字符-s:Silent mode. 不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这会很有帮助-t seconds:超时. 几秒钟后终止输入。read 会返回一个非零退出状态,若输入超时-u fd:使用文件描述符 fd 中的输入,而不是标准输入
*read选项例子:
*此脚本提示用户输入一个密码,若在10秒内没有完成输入,则脚本会退出并返回一个错误。因包含了一个 -s 选项,所以输入的密码不会出现在屏幕上。#!/bin/bash if read -t 10 -sp "Enter secret pass phrase > " secret_pass; then echo -e "\nSecret pass phrase = '$secret_pass'" else echo -e "\nInput timed out" >&2 exit 1 fi
*校正各种输入的示例程序:
#!/bin/bash invalid_input () { echo "Invalid input '$REPLY'" >&2 exit 1 } read -p "Enter a single item > " # input is empty (invalid) [[ -z $REPLY ]] && invalid_input # input is multiple items (invalid) (( $(echo $REPLY | wc -w) > 1 )) && invalid_input # is input a valid filename? if [[ $REPLY =~ ^[-[:alnum:]\._]+$ ]]; then echo "'$REPLY' is a valid filename." if [[ -e $REPLY ]]; then echo "And file '$REPLY' exists." else echo "However, file '$REPLY' does not exist." fi # is input a floating point number? if [[ $REPLY =~ ^-?[[:digit:]]*\.[[:digit:]]+$ ]]; then echo "'$REPLY' is a floating point number." else echo "'$REPLY' is not a floating point number." fi # is input an integer? if [[ $REPLY =~ ^-?[[:digit:]]+$ ]]; then echo "'$REPLY' is an integer." else echo "'$REPLY' is not an integer." fi else echo "The string '$REPLY' is not a valid filename." fi
*菜单驱动例子
*从逻辑上讲,这个脚本被分为两部分。第一部分显示菜单和用户输入。第二部分确认用户反馈,并执行 选择的行动#!/bin/bash # read-menu: a menu driven system information program clear echo " Please Select: 1. Display System Information 2. Display Disk Space 3. Display Home Space Utilization 0. Quit " read -p "Enter selection [0-3] > " if [[ $REPLY =~ ^[0-3]$ ]]; then if [[ $REPLY == 0 ]]; then echo "Program terminated." exit fi if [[ $REPLY == 1 ]]; then echo "Hostname: $HOSTNAME" uptime exit fi if [[ $REPLY == 2 ]]; then df -h exit fi if [[ $REPLY == 3 ]]; then if [[ $(id -u) -eq 0 ]]; then echo "Home Space Utilization (All Users)" du -sh /home/* else echo "Home Space Utilization ($USER)" du -sh $HOME fi exit fi else echo "Invalid entry." >&2 exit 1 fi