Shell编程入门总结(一)

本文的主要内容:

1、编写Shell脚本的一般步骤         

2、在Shell脚本中输出文本        

3、Shell脚本中的变量        

4、Shell脚本中的函数        

5、流程控制:if 分支结构       

6、Shell中读取键盘输入




一、编写Shell 脚本
一般步骤:1.编写一个脚本   2.使脚本文件可执行   3.把脚本放置到 shell 能够找到的地方

例如:
1.编写hello_world脚本
#!/bin/bash
# This is our first script.
echo 'Hello World!'

2.赋予可执行权限
chmod 700 hello_world

3.执行脚本
./hello_world


4.若想让系统中的每个用户都可以使用, 那么可将脚本放到 /usr/local/bin,系统管理员使用的脚本经常放到 /usr/local/sbin 目录下。


二、Shell中输出文本
  • 使用echo方式
例如:
echo "a string"

  • 使用"here document"方式(可以随意的嵌入引号)
格式如下:
command << token
text
token
这里的 command 是一个可以接受标准输入的命令名,token 是一个用来指示嵌入文本结束的字符串
把操作符"<<"改为 "<<-",shell 会忽略开头的 tab 字符,可使用缩进提高可读性


例如:
cat << _EOF_
a string
_EOF_

cat <<- _EOF_
	a string
_EOF_


  • 例子:使用 一个 here document 将一系列的命令传递到 ftp 程序中以从一个远端 FTP 服务器中得到一个文件
#!/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





三、Shell脚本中的变量
  • 创建变量或给变量赋值
variable=value(注:等号左右不能有空格)

  • 可以在同一行中对多个变量赋值
a=5 b="a string"

  • 使用变量
$variable 或 ${variable}

  • 例如
b="a string" 
c="a string and $b" 
mv $filename ${filename}1




四、Shell中的函数
  • 函数语法形式(其中name为函数名,commands为一系列包含在函数中的命令,函数中须至少包含一条命令,return为可选)
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 分支结构
  • if 语句语法如下
if commands; then
     commands
[elif commands; then
     commands...]
[else
     commands]
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新于 file2
file1 -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 等于 integer2
integer1 -ne integer2:integer1 不等于 integer2
integer1 -le integer2:integer1 小于或等于 integer2
integer1 -lt integer2:integer1 小于 integer2
integer1 -ge integer2:integer1 大于或等于 integer2
integer1 -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 - 从标准输入读取单行数据

*语法形式: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选项例子:
#!/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
*此脚本提示用户输入一个密码,若在10秒内没有完成输入,则脚本会退出并返回一个错误。因包含了一个 -s 选项,所以输入的密码不会出现在屏幕上。



  • 校正输入
*校正各种输入的示例程序:
#!/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
*从逻辑上讲,这个脚本被分为两部分。第一部分显示菜单和用户输入。第二部分确认用户反馈,并执行 选择的行动




参考:《The Linux Command Line》

你可能感兴趣的:(Linux基础)