Shell 编程入门

快速查询

数组

#!/bin/bash

array=(1 2 3 4 5)
for value in ${array[*]}
do
    echo $value
done

echo "The second number is ${array[1]}"

Control Flow

if
if command
then
    commands
fi

如果if后的command的退出状态码是0(执行成功),那么then后的命令会被执行

等价形式,只是利用;把then放在了同一行

if command; then
    commands
fi
if command
then
    commands
else
    commands
fi
if command1
then
    commands
elif command2
then
    commands
fi
case
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
esac
for
for var in list:
do
    commands
done

类C语言风格的for

for (( variable assignment ; condition ; iteration process ))
do
    commands
done

# example
for (( i=1; i <= 10; i++ ))
do
    echo $i
done

for (( a=1, b=10; a <=10; a++, b-- ))
do  
    echo "$b - $a"
done
while
while test command
do
    commands
done
#!/bin/bash
# while_statement.sh

i=5
while [ $i -gt 0 ]
do
    echo $i
    i=$[ $i - 1 ]
done
until

只有test命名退出状态码不是0时执行

until test commands
do
    other commands
done
循环控制 break 和 continue
break [n]
continue [n]

n指定跳出的层数,不写n时默认为1,当层。

处理用户输入

  • $0 程序名
  • $1 第一个参数
  • $n 第n个参
  • $# 输入参数的数量
  • $@ 命令行的所有参数, 遍历时是作为一个列表
  • $* 命令行的所有参数, 遍历时是一个字符串
total=$[ $1 + $2 ]
echo "First parameter is $1."
echo "Second parameter is $2."
echo "Total equals $total."

使用${!n}动态获取第n个参数的值

total=0
for (( i=1; i <= $#; i++ ))
do 
    echo "$i parameter is ${!i}"
    total=$[ $total + ${!i} ]
done
echo "Total equals $total."
total=0
for number in $@
do 
    echo "parameter is $number"
    total=$[ $total + $number ]
done
echo "Total equals $total."

必须要加入 #!/bin/bash

shell脚本会读取第一行, 来获取使用哪个shell运行脚本。

查看环境变量

echo $PATH

PATH环境变量被设置成只在一组目录中查找命令。将shell脚本所在的目录添加到PATH环境变量中,就可以运行shell。

注释

使用#进行注释

执行数学运算

要非常注意: bash shell 只支持整数运算 4 / 3 = 1

[Charles Shell]$ echo $[4 / 3]
1

expr 命令

注意:运算符两边要加空格, 有一些字符需要转移后使用

expr 1 + 2
expr 2 \* 3
#!/bin/bash
# An example of using the expr command
var1=10
var2=20
var3=$(expr $var2 / $var1)
echo The result is $var3

expr支持的运算符
[外链图片转存失败(img-UI33zU33-1566351510440)(md_images/expr_operations.png?raw=true)]

使用方括号$[运算式]

[Charles Shell]$ var1=$[1 + 2]
[Charles Shell]$ echo $var1
3
[Charles Shell]$ var2=$[$var1 * 2]
[Charles Shell]$ echo $var2
6
#!/bin/bash
var1=100
var2=50
var3=45
var4=$[$var1 * ($var2 - $var3)]
echo The final result is $var4

浮点数解决方案 bc —— bash内建计算器

bc实际上是一种编程语言
bc -q省略欢迎信息
在脚本中使用bc

variable=$(echo "options; expression" | bc)

bc支持:

  • 数字(整数和浮点数)
  • 变量(简单变量和数组)
  • 注释(# 或 /* */)
  • 表达式
  • 编程语句(if-then 等)
  • 函数
[Charles Shell]$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
12 * 5.4
64.8

1 + 2
3
quit
[Charles Shell]$ bc -q
# 浮点数使用scale指定保留位数
1/2
0
scale=4
1/2
.5000
1/3
.3333
2/3
.6666

var1 = 10
var1 * 2
20
var2 = var1 / 5
print var2
2.0000
quit
#!/bin/bash
# bc.sh
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
 #!/bin/bash
 # bc2
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(bc << EOF
scale = 4
a1 = ( $var1 * $var2)
b1 = ($var3 * $var4)
a1 + b1
EOF
)
echo The final answer for this mess is $var5

显示信息 echo

  1. 直接显示字符echo Hello world
  2. 使用单引号或双引号echo "Hello world"echo 'Hello world'
  3. -n参数去掉换行符 echo -n "Hello " ; echo "world"

变量

环境变量

使用set命令可以查看当前环境的完整环境变量列表

用户变量

  • 使用变量:$变量名${变量名}使用环境变量,后者更提供了更明确的变量名,

    welcome="Hello"
    echo $welcome   # Hello
    echo ${welcome},world # Hello,world
    
  • 定义变量:变量名=变量值,注意等号的两边不能有空格。shell脚本会自动决定变量值的数据类型。在脚本的整个生命周期里,shell脚本中定义的变量 会一直保持着它们的值,但在shell脚本结束时会被删除掉。

    welcome="Hello world"
    positive_number=12
    negative_number=-12
    
    value1=10
    value2=$value1
    echo The resulting value is $value2
    

命令替换(将命令的结果赋值给变量)

  • 使用反引号字符"`"
  • 使用$()的形式
# generate_log.sh
today=$(date +%y%m%d)
ls -al /usr/bin > log.$today

重定向输入和输出

输出重定向

command > outputfile, 如果outputfile存在,会用新文件覆盖原有文件。

command >> outputfile, 这条命令会在文件后追加command的输出。

输入重定向

command < inputfile, 如wc < README.md
command << marker, 内联输入重定向(inline input redirection)。使用这种方法直接在shell界面上输入要重定向到command的命令,而无需使用文件进行重定向。例如

# wc的输出分别对应  文本行数 文本词数 文本字节数
[Charles Shell]$ wc << EOF
> haha
> 1234
> 12345
> 
> 678
> EOF
       5       4      21

管道(piping)(将一个命令的输出作为另一个命令的输入)

command1 | command2, command1的输出作为command2的输入。Linux会同时运行这两个命令,并在系统的内部将其连接起来。在第一个命令产生输出后会立即送入第二个命令。数据传输不会用到任何中间文件或缓冲区

[Charles Shell]$ ls -al | grep README.md 
-rw-r--r--@  1 Charles  staff  1725 Jul 22 10:23 README.md

如果不使用管道,而使用重定向,则需要一个中间文件

[Charles Shell]$ ls -al > temp.txt
[Charles Shell]$ grep README.md < temp.txt
-rw-r--r--@  1 Charles  staff  1725 Jul 22 10:23 README.md

在一条命名中可以使用任意条管道

$ rpm -qa | sort | more

可以搭配重定向

$ rpm -qa | sort > rpm.list

退出脚本

  • Linux使用$?查看上一条命令的退出状态码。
  • 一个成功的命令的退出状态码是0。
  • 退出状态码是0或正整数, 范围在0-255

在脚本中使用

#!/bin/bash
# testing the exit status
var1=10
var2=30
var3=$[$var1 + $var2]
exit $var3

Control Flow

if

if command
then
    commands
fi

如果if后的command的退出状态码是0(执行成功),那么then后的命令会被执行

等价形式,只是利用;把then放在了同一行

if command; then
    commands
fi
if command
then
    commands
else
    commands
fi
if command1
then
    commands
elif command2
then
    commands
fi

示例:

#!/bin/bash
# Testing nested ifs - use elif & else #
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."
else
   echo "The user $testuser does not exist on this system."
   echo "And, $testuser does not have a directory."
fi

test

方括号形式表示

注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。

if [ condition ]
then
    commands
fi
直接使用命令

格式

test condition

只写test 退出状态码 0

#!/bin/bash
# Testing the test command #
my_variable="Full"

if test $my_variable
then
   echo "The $my_variable expression returns a True"
else
   echo "The $my_variable expression returns a False"
fi
$
$ ./test6.sh
The Full expression returns a True 
test支持的比较形式

test 支持3类判断

  • 数值比较
  • 字符串比较
  • 文件比较

1.数值比较
[外链图片转存失败(img-fkOlYmQe-1566351510442)(md_images/test_value_compare.png?raw=true)]

注意,bash shell只能处理整数,涉及到浮点数的条件会出错

[Charles Shell]$ test 1 -eq 2[Charles Shell]$ $?
bash: 1: command not found
[Charles Shell]$ test 1 -eq 1
[Charles Shell]$ $?
bash: 0: command not found
#!/bin/bash
# if_statement.sh
value=10

if [ $value -gt 5 ]
then
    echo "Value great than 5!"
fi

benchmark=20
if [ $value -gt $benchmark ]
then
    echo "Value great than benchmarl"
else
    echo "Value less than or equal benchmark"
fi

# result:
# Value great than 5!
# Value less than or equal benchmark

2. 字符串比较
[外链图片转存失败(img-h3f9hJNG-1566351510443)(md_images/test_string_compare.png?raw=true)]

字符串比较时,大小写和标点都会考虑。
注意:

  • 要考虑">“和”<“号的转义,写成”>"
  • 不同的命令在处理大写字母和小写字母上的顺序不同,有时是大写字符大于小写字符,有时相反。

3. 文件比较
用于检测文件状态
[外链图片转存失败(img-Xsz2Vqcr-1566351510443)(md_images/test_file_compare.png?raw=true)]

复合条件

  • [ condition1 ] && [ condition2 ]
  • [ condition1 ] || [ condition2 ]
#!/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

用于数学表达式的双括号

(( expression ))

除了标准数学运算符 + - * \ ,还支持如下的表
[外链图片转存失败(img-ImjjPBhu-1566351510444)(md_images/symbol.png?raw=true)]

#!/bin/bash
# symbol.sh

value=10
if (( $value * 2 > 15 ))
then
    echo "value * 2 > 15"
fi

# value=10
# if (( ${value} / 2 > 5))
# then
#     echo "value / 2 > 5"
# fi

val1=10
#
if (( $val1 ** 2 > 90 ))
then
    (( val2 = $val1 ** 2 ))
    echo "The square of $val1 is $val2"
fi

# result
# value * 2 > 15
# The square of 10 is 100

使用双方括号利用模式匹配处理字符串

[[ expression ]],双方括号中可以使用模式匹配来处理字符串

#!/bin/bash
# using pattern matching 
if [[ $USER == r* ]]
then
echo "Hello $USER"
else 5
    echo "Sorry, I do not know you"
fi

case

case variable in
pattern1 | pattern2) commands1;;
pattern3) commands;;
esac
#!/bin/bash
# using the case command #
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

for

for var in list:
do
    commands
done
#!/bin/bash
# for_statement.sh

for name in aa bb cc dd
do
    echo $name
done

echo '\nsecond case'

for word in "I don't know if this'll work"
do 
    echo $word
done

echo '\nthird case:'
for word in I don\'t know if "this'll" work
do
    echo $word
done

echo "\nuse a list variable in for statement"

list="aa bb cc"
list=${list}" dd"
for word in $list
do
    echo $word
done

echo "\nuse a list from command"
for file_name in $(ls)
do
    echo $file_name
done

echo "\n define yourself IFS"
# define yourself IFS(internal field separator)
# the default value is space, tab and enter.
IFS_OLD=$IFS
IFS=$'\n'
for file_info in $(ls -l)
do
    echo $file_info
done
# define more than one values to IFS
# IFS=$:;
IFS=$IFS_OLD

echo "read files in another method"
for file_path in ./md_images/*
do 
    echo $file_path
done

echo 

path=$(pwd)
for file_path in $path/*
do
    echo $file_path
done

echo 

for file_name in $(ls $path)
do
    echo $file_name
done

C语言风格的forxunhuan

for (( variable assignment ; condition ; iteration process ))
do
    commands
done
for (( i=1; i <= 10; i++ ))
do
    echo $i
done

while

while test command
do
    commands
done
#!/bin/bash
# while_statement.sh

i=5
while [ $i -gt 0 ]
do
    echo $i
    i=$[ $i - 1 ]
done

until

只有test命名退出状态码不是0时执行

until test commands
do
    other commands
done
#!/bin/bash
# until_statement.sh

var=10

until [ $var -eq 0 ]
do 
    echo $var
    var=$[ $var - 1 ]
done

循环控制 break 和 continue

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"

break可以指定跳出循环的层数

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

处理用户输入

  • $0 程序名
  • $1 第一个参数
  • $n 第n个参
  • $# 输入参数的数量
  • $@ 命令行的所有参数, 遍历时是作为一个列表
  • $* 命令行的所有参数, 遍历时是一个字符串
#!/bin/bash
# add.sh

if [ ! -n "$1" ]
then
    echo "You should input the first parameter."
    exit 2
fi

if [ ! -n "$2" ]
then    
    echo "You shoule input the second parameter."
    exit 2
fi

total=$[ $1 + $2 ]
echo "First parameter is $1."
echo "Second parameter is $2."
echo "Total equals $total."

使用${!n}动态获取第n个参数的值

#!/bin/bash
# add_v2.sh

if [ ! -n "$1" ]
then
    echo "You should input the first parameter."
    exit 2
fi

total=0
for (( i=1; i <= $#; i++ ))
do 
    echo "$i parameter is ${!i}"
    total=$[ $total + ${!i} ]
done
echo "Total equals $total."
#!/bin/bash
# add_v3.sh

if [ ! -n "$1" ]
then
    echo "You should input the first parameter."
    exit 2
fi

total=0
for number in $@
do 
    echo "parameter is $number"
    total=$[ $total + $number ]
done
echo "Total equals $total."

获取用户输入(动态交互)

read variable
echo -n "Enter your name: "
read name
echo $name
read -p "Please enter your age: " age

读取文件

#!/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"

函数

shell将所有的函数都作为一个命令

function name {
    commands
}

向函数中传递参数

function add {
    if [ ! -n "$1" ]
    then
        echo "You should input the first parameter."
        exit 2
    fi

    total=0
    for number in $@
    do 
        total=$[ $total + $number ]
    done
    echo $total
}

read -p 'The list of numbers: ' numbers
echo "the sum of numbers is $(add $numbers)"

使用return返回退出状态码
使用$() 或 "``"来接受函数的结果

#/bin/bash

function times2 {
    read -p "Enter a value: " value
    echo $[ $value * 2 ]
}

result=$(times2)
echo "New value is $result."

函数内部的变量默认是全局变量
如果想使用局部变量需要在声明时加上local关键字

function times2 {
    local value
    read -p "Enter a value: " value
    echo $[ $value * 2 ]
}

也可以在声明的同时赋值

function times2 {
    local value=5
    echo "====local in times2 $value===="
    read -p "Enter a value: " value
    echo $[ $value * 2 ]
}

递归

#!/bin/bash
# 计算阶乘,展示递归的用法

function factorial {
    if [ $1 -eq 1 ]
    then
        echo 1
    else 
        local temp=$[ $1 - 1 ]
        local result=$(factorial $temp)
        echo $[ $result * $1 ]
    fi 
}

read -p "Enter value: " value
result=$(factorial $value)
echo "The factorial of $value is: $result"

调用函数库

# 函数库文件
function factorial {
    if [ $1 -eq 1 ]
    then
        echo 1
    else 
        local temp=$[ $1 - 1 ]
        local result=$(factorial $temp)
        echo $[ $result * $1 ]
    fi 
}
#!/bin/bash
# 使用函数库的文件

# 使用source导入函数库
source ./fac_func.sh
echo $(factorial 5)

在命令行上创建函数

[Charles Shell]$ function add {
> echo $[ $1 + $2 ]
> }
[Charles Shell]$ add 1 2
3

数组

#!/bin/bash

array=(1 2 3 4 5)
for value in ${array[*]}
do
    echo $value
done

echo "The second number is ${array[1]}"

其他

  1. source命令,source会再当前shell的上下文中执行命令,而不是创建一个新的shell。其有一个快捷的别名.,如. ./myscript.sh
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值