shell教程

Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。 在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。

! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。

1、两种运行方式

chmod +x test.sh ./test.sh 直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的

/bin/bash test.sh 这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

2、变量

  • 注意,变量名和等号之间不能有空格
  • 使用一个定义过的变量,只要在变量名前面加美元符号即可
  • 推荐给所有变量加上花括号,这是个好的编程习惯。即:echo ${your_name}
  • 注意,第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美元符($)
  • 只读变量:变量定义后换行readonly your_name
  • 使用 unset 命令可以删除变量, 不能删除只读变量

3、bash上一步参数

!^ !$ !:1

强大如斯的:ctrl + r

4、字符串的单双引号

单引号字符串的限制: 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的; 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

双引号的优点: 双引号里可以有变量 双引号里可以出现转义字符

获取字符串长度 string="abcd" echo ${#string} #输出 4 提取子字符串 以下实例从字符串第 2 个字符开始截取 4 个字符:

string="runoob is a great site" echo ${string:1:4} # 输出 unoo 注意:第一个字符的索引值为 0。

查找子字符串 查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):

string="runoob is a great site" echo expr index "$string" io # 输出 4 注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。

5、数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。

在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。

使用 @ 符号可以获取数组中的所有元素,例如: echo ${array_name[@]}

获取数组的长度 获取数组长度的方法与获取字符串长度的方法相同,例如:

# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}

6、多行注释

:<<EOF
注释内容...
注释内容...
注释内容...
EOF
EOF 也可以使用其他符号,如'!:

:<<'
注释内容...
注释内容...
注释内容...
'

:<<!
注释内容...
注释内容...
注释内容...
!

7、Linux 的字符串截取很有用

#!/bin/bash
# 字符串截取(界定字符本身也会被删除)
str="www.runoob.com/linux/linux-shell-variable.html"
echo "str       : ${str}"
echo "str#*/    : ${str#*/}"   # 从 字符串开头 删除到 左数第一个'/'
echo "str##*/   : ${str##*/}"  # 从 字符串开头 删除到 左数最后一个'/'
echo "str%/*    : ${str%/*}"   # 从 字符串末尾 删除到 右数第一个'/'
echo "str%%/*   : ${str%%/*}"  # 从 字符串末尾 删除到 右数最后一个'/'
echo
echo "str#/*    : ${str#/*}"   # 无效果
echo "str##/*   : ${str##/*}"  # 无效果
echo "str%*/    : ${str%*/}"   # 无效果
echo "str%%*/   : ${str%%*/}"  # 无效果

有八种方法。 假设有变量 var=http://www.aaa.com/123.htm

  1. 号截取,删除左边字符,保留右边字符。

echo ${var#//} 其中 var 是变量名,# 号是运算符,// 表示从左边开始删除第一个 // 号及左边的所有字符

即删除 http://

结果是 :www.aaa.com/123.htm

  1. 号截取,删除左边字符,保留右边字符。

echo ${var##*/}

*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符

即删除 http://www.aaa.com/

结果是 123.htm

  1. %号截取,删除右边字符,保留左边字符

echo ${var%/} %/ 表示从右边开始,删除第一个 / 号及右边的字符

结果是:http://www.aaa.com

  1. %% 号截取,删除右边字符,保留左边字符

echo ${var%%/} %%/ 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符

结果是:http:

  1. 从左边第几个字符开始,及字符的个数

echo ${var:0:5} 其中的 0 表示左边第一个字符开始,5 表示字符的总个数。

结果是:http:

  1. 从左边第几个字符开始,一直到结束。

echo ${var:7} 其中的 7 表示左边第8个字符开始,一直到结束。

结果是 :www.aaa.com/123.htm

  1. 从右边第几个字符开始,及字符的个数

echo ${var:0-7:3} 其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。

结果是:123

  1. 从右边第几个字符开始,一直到结束。

echo ${var:0-7} 表示从右边第七个字符开始,一直到结束。

结果是:123.htm

注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)

8、expr命令

计算字符长度也可是使用 length:

string="hello,everyone my name is xiaoming" expr length "$string" 输出:34

注意:string字符串里边有空格,所以需要添加双引号

使用 expr 命令时,表达式中的运算符左右必须包含空格,如果不包含空格,将会输出表达式本身:

expr 5+6 // 直接输出 5+6 expr 5 + 6 // 输出 11 对于某些运算符,还需要我们使用符号"\"进行转义,否则就会提示语法错误。

expr 5 6 // 输出错误 expr 5 \ 6 // 输出30

9、read 命令用于获取键盘输入信息

-p 参数由于设置提示信息:

read -p "input a val:" a    #获取键盘输入的 a 变量数字
read -p "input b val:" b    #获取键盘输入的 b 变量数字
r=$[a+b]                    #计算a+b的结果 赋值给r  不能有空格
echo "result = ${r}"        #输出显示结果 r

10、脚本参数

$1:脚本名称 $2:第一个参数 $n:第n个参数

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。

如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。

$$ |脚本运行的当前进程ID号 $! |后台运行的最后一个进程的ID号 $@ |与$*相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。 $- |显示Shell使用的当前选项,与set命令功能相同。 $? |显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

$* 与 $@ 区别

相同点:都是引用所有参数。 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。

11、Shell 中的中括号用法总结

算术比较

对变量或值进行算术条件判断:

[ $var -eq 0 ]  # 当 $var 等于 0 时,返回真
[ $var -ne 0 ]  # 当 $var 不等于 0 时,返回真

需要注意的是 [ 与 ] 与操作数之间一定要有一个空格,否则会报错。比如下面这样就会报错:

[$var -eq 0 ]  或 [ $var -ne 0]

其他比较操作符:

操作符 意义
-gt 大于
-lt 小于
-ge 大于或等于
-le 小于或等于

可以通过 -a (and) 或 -o (or) 结合多个条件进行测试:

[ $var1 -ne 0 -a $var2 -gt 2 ]  # 使用逻辑与 -a
[ $var1 -ne 0 -o $var2 -gt 2 ]  # 使用逻辑或 -o

文件系统属性测试

使用不同的条件标志测试不同的文件系统属性。

操作符 意义
[ -f $file_var ] 变量 $file_var 是一个正常的文件路径或文件名 (file),则返回真
[ -x $var ] 变量 $var 包含的文件可执行 (execute),则返回真
[ -d $var ] 变量 $var 包含的文件是目录 (directory),则返回真
[ -e $var ] 变量 $var 包含的文件存在 (exist),则返回真
[ -c $var ] 变量 $var 包含的文件是一个字符设备文件的路径 (character),则返回真
[ -b $var ] 变量 $var 包含的文件是一个块设备文件的路径 (block),则返回真
[ -w $var ] 变量 $var 包含的文件可写(write),则返回真
[ -r $var ] 变量 $var 包含的文件可读 (read),则返回真
[ -L $var ] 变量 $var 包含是一个符号链接 (link),则返回真

字符串比较

在进行字符串比较时,最好使用双中括号 [[ ]]. 因为单中括号可能会导致一些错误,因此最好避开它们。

检查两个字符串是否相同:

[[ $str1 = $str2 ]]

当 str1等于str1等于str2 时,返回真。也就是说,str1 和 str2 包含的文本是一样的。其中的单等于号也可以写成双等于号,也就是说,上面的字符串比较等效于 [[ $str1 == $str2 ]]。

注意 = 前后有一个空格,如果忘记加空格, 就变成了赋值语句,而非比较关系了。

字符串的其他比较情况:

操作符 意义
[[ $str1 != $str2 ]] 如果 str1 与 str2 不相同,则返回真
[[ -z $str1 ]] 如果 str1 是空字符串,则返回真
[[ -n $str1 ]] 如果 str1 是非空字符串,则返回真

使用逻辑运算符 && 和 || 可以轻松地将多个条件组合起来, 比如:

str1="Not empty"
str2=""
if [[ -n $str1 ]] && [[ -z $str2 ]];
then
  echo str1 is nonempty and str2 is empty string.
fi

test 命令也可以从来执行条件检测,用 test 可以避免使用过多的括号,[] 中的测试条件同样可以通过 test 来完成。

if [ $var -eq 0 ]; then echo "True"; fi

等价于:

if test $var -eq 0; then echo "True"; fi

12、数组

数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小(与 PHP 类似)。

与大部分编程语言类似,数组元素的下标由0开始。

Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:

array_name=(value1 value2 ... valuen)

使用@ 或 * 可以获取数组中的所有元素。

获取数组长度的方法与获取字符串长度的方法相同。

my_array=(A B "C" D)

echo "第一个元素为: ${my_array[0]}"
echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"
echo "数组元素个数为: ${#my_array[*]}"
echo "数组元素个数为: ${#my_array[@]}"

i=2
echo "i可以直接下标: ${arr[i]}"
echo "i也可以取其值: ${arr[$i]}"

遍历数组

#!/bin/bash

my_arry=(a b "c","d" abc)
echo "-------FOR循环遍历输出数组--------"
for i in ${my_arry[@]};
do
  echo $i
done

echo "-------::::WHILE循环输出 使用 let i++ 自增:::::---------"
j=0
while [ $j -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$j]}
  let j++
  let "j++"
  let j+=1
  j=$[$j+1]
done

字符串转数组:

#!/bin/bash

words="aaa bbb ccc"

#字符串转数组,空格是分隔符
array=(${words// / })
#打印数组最后一个成员
echo ${array[${#array[*]}-1]}
#打印数组长度
echo ${#array[*]}

#字符串不转换为数组,在循环实现以空格为分隔符打印每个成员
for word in ${words}; do
    echo ${word}
done

13、/bin/bash和/bin/sh的区别

bash遇到脚本错误继续执行后面 sh遇到脚本错误不再执行后面代码 因此推荐使用bash

  1. sh一般设成bash的软链 [work@zjm-testing-app46 cy]$ ll /bin/sh lrwxrwxrwx 1 root root 4 Nov 13 2006 /bin/sh -> bash
  2. 在一般的linux系统当中(如redhat),使用sh调用执行脚本相当于打开了bash的POSIX标准模式
  3. 也就是说 /bin/sh 相当于 /bin/bash --posix

所以,sh跟bash的区别,实际上就是bash有没有开启posix模式的区别

so,可以预想的是,如果第一行写成 #!/bin/bash --posix,那么脚本执行效果跟#!/bin/sh是一样的(遵循posix的特定规范,有可能就包括这样的规范:“当某行代码出错时,不继续往下解释”)

14、Shell 基本运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。

expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

例如,两个数相加(注意使用的是反引号 \`* 而不是单引号 *'**):

实例

#!/bin/bash

val=`expr 2 + 2`
echo "两数之和为 : $val"

执行脚本,输出结果如下所示:

两数之和为 : 4

两点注意:

  • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。
  • 完整的表达式要被 包含,注意这个字符不是常用的单引号,在 Esc 键下边。
  • 乘法需要反斜杠,如val=`expr $a \* $b`

字符串运算符

注意判断相等。

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否不为 0,不为 0 返回 true。 [ -n "$a" ] 返回 true。
$ 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。

文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。

属性检测描述如下:

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是有名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

其他检查符:

  • -S: 判断某文件是否 socket。
  • -L: 检测文件是否存在并且是一个符号链接。

就是 EQUAL等于

NE 就是 NOT EQUAL不等于

GT 就是 GREATER THAN大于 

LT 就是 LESS THAN小于

GE 就是 GREATER THAN OR EQUAL 大于等于

LE 就是 LESS THAN OR EQUAL 小于等于

使用 [[ ... ]] 条件判断结构,而不是 [ ... ],能够防止脚本中的许多逻辑错误。比如,&&||<> 操作符能够正常存在于 [[ ]] 条件判断结构中,但是如果出现在 [ ] 结构中的话,会报错。

推荐用 $() 代替 ``:

val=`expr 10 + 20`

val=$(expr 10 + 20)

[] 表达式

注意:在 [] 表达式中,常见的 >, < 需要加转义字符,表示字符串大小比较,以 acill 码位置作为比较。不直接支持 >, < 运算符,还有逻辑运算符 || 、&& ,它需要用 -a[and] –o[or] 表示。

[[ ]] 表达式

注意:[[]] 运算符只是 [] 运算符的扩充。能够支持 >, < 符号运算不需要转义符,它还是以字符串比较大小。里面支持逻辑运算符:|| && ,不再使用 -a -o。

15、Shell echo命令

1.显示换行

echo -e "OK! \n" # -e 开启转义
echo "It is a test"

输出结果:

OK!

It is a test

2.显示不换行

#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"

输出结果:

OK! It is a test

3.原样输出字符串,不进行转义或取变量(用单引号)

echo '$name\"'

输出结果:

$name\"

4.显示命令执行结果

echo `date`

注意: 这里使用的是反引号 `, 而不是单引号 '

结果将显示当前日期

Thu Jul 24 10:08:46 CST 2014
单双引号 能否引用变量 能否引用转移符 能否引用文本格式符(如:换行符、制表符)
单引号
双引号
无引号

16、Shell printf 命令

#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876

执行脚本,输出结果如下所示:

姓名     性别   体重kg
郭靖     男      66.12
杨过     男      48.65
郭芙     女      47.99

%s %c %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%c 输出一个字符,%f 输出实数,以小数形式输出。

%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。

%-4.2f 指格式化为小数,其中 .2 指保留2位小数。

17、Shell test 命令

Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

符号含义:

  1. eq (equal的缩写),表示等于为真

  2. ne (not equal的缩写),表示不等于为真

  3. gt (greater than的缩写),表示大于为真

  4. ge (greater&equal的缩写),表示大于等于为真

  5. lt (lower than的缩写),表示小于为真

  6. le (lower&equal的缩写),表示小于等于为真

除非你清楚自己在干什么,否则请避免在”Shell test命令“中使用单引号——使用它可能会导致难以察觉的错误,尤其是对于Shell初学者。

[] 内部两端要有空格、-d 参数和其他内容之间要有空格, 如果 then 另起一行的话 then 前不需要加 ; 否则需要在 then 前加 ;

相当于[]

18、Shell 流程控制

实例:注意是空格

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

输出结果:

The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

无限循环

无限循环语法格式:

while :
do
    command
done

或者

while true
do
    command
done

或者

for (( ; ; ))

until 循环

until 循环执行一系列命令直至条件为 true 时停止。

until 循环与 while 循环在处理方式上刚好相反。重点:判断方式相反。

一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

case实例

echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac

for 循环可以做到与 C 中相似,但并不完全相同。

通常情况下 shell 变量调用需要加 $,但是 for 的 (()) 中不需要,下面来看一个例子:

#!/bin/bash
for((i=1;i<=5;i++));do
    echo "这是第 $i 次调用";
done;

19、shell函数

可以带function fun() 定义,也可以直接fun() 定义,不带function。

#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "输入第二个数字: "
    read anotherNum
    echo "两个数字分别为 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

results matching ""

    No results matching ""