shell全面入门教程--IT隐匿者

Shell入门

Shell 变量

your_name="qinjx"
echo $your_name
echo ${your_name}

for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done

如果不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。

推荐给所有变量加上花括号,这是个好的编程习惯。
删除变量

使用 unset 命令可以删除变量。语法:

unset variable_name

#!/bin/sh
myUrl="http://c.biancheng.net/shell/"
unset myUrl
echo $myUrl

没任何输出

Shell 中有两种方式可以完成命令替换,一种是反引号,一种是$(),使用方法如下:

variable=`commands`
variable=$(commands)

其中,variable 是变量名,commands 是要执行的命令。commands 可以只有一个命令,也可以有多个命令,多个命令之间以分号`;`分隔。

例如,date 命令用来获得当前的系统时间,使用命令替换可以将它的结果赋值给一个变量。

data是一个命令

#!/bin/bash
begin_time=`date`    #开始时间,使用``替换
sleep 20s            #休眠20秒
finish_time=$(date)  #结束时间,使用$()替换
echo "Begin time: $begin_time"
echo "Finish time: $finish_time"



运行脚本,20 秒后可以看到输出结果:
Begin time: 2019年 04月 19日 星期五 09:59:58 CST
Finish time: 2019年 04月 19日 星期五 10:00:18 CST

Shell $?:获取函数返回值或者上一个命令的退出状态


1) $? 获取上一个命令的退出状态

编写下面的代码,并保存为 test.sh:

#!/bin/bash
if [ "$1" == 100 ]
then
   exit 0  #参数正确,退出状态为0
else
   exit 1  #参数错误,退出状态1
fi

exit表示退出当前 Shell 进程,我们必须在新进程中运行 test.sh,否则当前 Shell 会话(终端窗口)会被关闭,我们就无法取得它的退出状态了。

例如,运行 test.sh 时传递参数 100:

[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ bash ./test.sh 100  #作为一个新进程运行
[mozhiyan@localhost demo]$ echo $?
0

再如,运行 test.sh 时传递参数 89:

[mozhiyan@localhost demo]$ bash ./test.sh 89  #作为一个新进程运行
[mozhiyan@localhost demo]$ echo $?
1

2) $? 获取函数的返回值

编写下面的代码,并保存为 test.sh:

#!/bin/bash
#得到两个数相加的和
function add(){
    return `expr $1 + $2`
}
add 23 50  #调用函数
echo $?  #获取函数返回值  73
变量类型

运行shell时,会同时存在三种变量:

  • 1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  • 2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • 3) shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
单引号字符串的限制:
  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3


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

string="runoob is a great site"
echo ${string:1:4} # 输出 unoo
查找子字符串
查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):
string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。

Shell 数组

在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:

array_name=(value0 value1 value2 value3)

array_name=(
value0
value1
value2
value3
)

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

读取数组

读取数组元素值的一般格式是:

${数组名[下标]}

例如:

valuen=${array_name[n]}

使用 @ 符号可以获取数组中的所有元素,例如:

echo ${array_name[@]}


使用@或*可以获取数组中的所有元素,例如:

${nums[*]}
${nums[@]}

获取数组的长度

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

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


my_array=(A B "C" D)

echo "第一个元素为: ${my_array[0]}" # A
echo "第二个元素为: ${my_array[1]}" # B

echo "数组的元素为: ${my_array[*]}"#数组的元素为: A B C D
echo "数组的元素为: ${my_array[@]}"#数组的元素为: A B C D

#!/bin/bash
nums=(29 100 13)
echo ${#nums[*]}
#向数组中添加元素
nums[10]="http://c.biancheng.net/shell/"
echo ${#nums[@]}
echo ${#nums[10]}
#删除数组元素
unset nums[1]
echo ${#nums[*]}
运行结果:
3
4
29
3

数组的拼接

所谓 Shell 数组拼接(数组合并),就是将两个数组连接成一个数组。

拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。具体格式如下:
array_new=(${array1[@]}  ${array2[@]})
array_new=(${array1[*]}  ${array2[*]})

两种方式是等价的,选择其一即可。其中,array1 和 array2 是需要拼接的数组,array_new 是拼接后形成的新数组。

下面是完整的演示代码:
#!/bin/bash
array1=(23 56)
array2=(99 "http://c.biancheng.net/shell/")
array_new=(${array1[@]} ${array2[*]})
echo ${array_new[@]}  #也可以写作 ${array_new[*]}
运行结果:
23 56 99 http://c.biancheng.net/shell/

Shell 注释

# 开头的行就是注释,会被解释器忽略。

通过每一行加一个 # 号设置多行注释,像这样:

#--------------------------------------------
# 这是一个注释
# author:菜鸟教程
# site:www.runoob.com
# slogan:学的不仅是技术,更是梦想!
#--------------------------------------------
##### 用户配置区 开始 #####
#
#
# 这里可以添加脚本描述信息
# 
#
##### 用户配置区 结束  #####

如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?

每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。

多行注释

多行注释还可以使用以下格式:

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

EOF 也可以使用其他符号:

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

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

Shell 传递参数

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

实例
以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名(包含文件路径):

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

echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
另外,还有几个特殊字符用来处理参数:

参数处理	说明
$#	传递到脚本的参数个数
$*	以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$	脚本运行的当前进程ID号
$!	后台运行的最后一个进程的ID号
$@	与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$-	显示Shell使用的当前选项,与set命令功能相同。
$?	显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

echo "Shell 传递参数实例!";
echo "第一个参数为:$1";

echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
第一个参数为:1
参数个数为:3
传递的参数作为一个字符串显示:1 2 3
另外,还有几个特殊字符用来处理参数:

参数处理	说明
$#	传递到脚本的参数个数
$*	以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$	脚本运行的当前进程ID号
$!	后台运行的最后一个进程的ID号
$@	与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$-	显示Shell使用的当前选项,与set命令功能相同。
$?	显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

echo "Shell 传递参数实例!";
echo "第一个参数为:$1";

echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
第一个参数为:1
参数个数为:3
传递的参数作为一个字符串显示:1 2 3
$* 与 $@ 区别:

相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

echo "-- \$* 演示 ---"
for i in "$*"; do
    echo $i
done

echo "-- \$@ 演示 ---"
for i in "$@"; do
    echo $i
done
执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
-- $* 演示 ---
1 2 3
-- $@ 演示 ---
1
2
3

Shell 基本运算符

算术运算符

下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
+加法expr $a + $b 结果为 30。
-减法expr $a - $b 结果为 -10。
*乘法expr $a \* $b 结果为 200。
/除法expr $b / $a 结果为 2。
%取余expr $b % $a 结果为 0。
=赋值a=$b 将把变量 b 的值赋给 a。
==相等。用于比较两个数字,相同则返回 true。[ $a == $b ] 返回 false。
!=不相等。用于比较两个数字,不相同则返回 true。[ $a != $b ] 返回 true。

**注意:**条件表达式要放在方括号之间,并且要有空格,例如: [ a = = a== a==b] 是错误的,必须写成 [ $a == $b ]

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

a=10
b=20

val=****expr** $a + $b**
echo “a + b : $val”

val=****expr** $a - $b**
echo “a - b : $val”

val=****expr** $a \***** $b**
echo “a * b : $val”

val=****expr** $b **/** $a**
echo “b / a : $val”

val=****expr** $b **%** $a**
echo “b % a : $val”

if [ $a == $b ]
then
echo “a 等于 b”
fi
if [ $a != $b ]
then
echo “a 不等于 b”
fi

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

a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等于 b

布尔运算符

下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
!非运算,表达式为 true 则返回 false,否则返回 true。非,并非不等于( != )[ ! false ] 返回 true。
-o或运算,有一个表达式为 true 则返回 true。 or[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a与运算,两个表达式都为 true 才返回 true。 and[ $a -lt 20 -a $b -gt 100 ] 返回 false。

关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
-eq检测两个数是否相等,相等返回 true。equit[ $a -eq $b ] 返回 false。
-ne检测两个数是否不相等,不相等返回 true。 ont equit[ $a -ne $b ] 返回 true。
-gt检测左边的数是否大于右边的,如果是,则返回 true。 greater than[ $a -gt $b ] 返回 false。
-lt检测左边的数是否小于右边的,如果是,则返回 true。 less than[ $a -lt $b ] 返回 true。
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。[ $a -ge $b ] 返回 false。
-le检测左边的数是否小于等于右边的,如果是,则返回 true。[ $a -le $b ] 返回 true。

逻辑运算符

以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
&&逻辑的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
||逻辑的 OR[[ $a -lt 100

字符串运算符

下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:

运算符说明举例
=检测两个字符串是否相等,相等返回 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。

文件测试运算符

操作符说明举例
-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。

常用函数echo print

echo 显示换行

我们可以添加-e参数来让 echo 命令解析转义字符。例如:

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

echo 显示不换行

我们可以添加-e参数来让 echo 命令解析转义字符。例如:

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

不换行
echo 命令输出结束后默认会换行,如果不希望换行,可以加上-n参数,如下所示:
echo -n "${name} is ${age} years old, "
echo -n "${height}cm in height "

echo 显示结果定向至文件

echo "It is a test" > myfile

接下来,我来用一个脚本来体现 printf 的强大功能:

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位小数。四舍五入

*#!/bin/bash*
*# author:菜鸟教程*
*# url:www.runoob.com*
 
*# format-string为双引号*
**printf** "%d %s**\n**" 1 "abc"

*# 单引号与双引号效果一样*
**printf** '%d %s\n' 1 "abc"

*# 没有引号也可以输出*
**printf** **%**s abcdef

*# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用*
**printf** **%**s abc def

**printf** "%s**\n**" abc def

**printf** "%s %s %s**\n**" a b c d e f g h i j

*# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替*
**printf** "%s and %d **\n**"

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

1 abc
1 abc
abcdefabcdefabc
def
a b c
d e f
g h i
j  
 and 0

Shell 流程控制

以下实例判断两个变量是否相等:

iF流程控制

test 通常和 if 语句一起使用,并且大部分 if 语句都依赖 test。

read age
if test $age -le 2; then
    echo "婴儿"
elif test $age -ge 3 && test $age -le 8; then
    echo "幼儿"
elif [ $age -ge 9 ] && [ $age -le 17 ]; then
    echo "少年"
elif [ $age -ge 18 ] && [ $age -le 25 ]; then
    echo "成年"
elif test $age -ge 26 && test $age -le 40; then
    echo "青年"
elif test $age -ge 41 && [ $age -le 60 ]; then
    echo "中年"
else
    echo "老年"
fi


a=10
b=20
if [ $a == $b ]
then
   echo "a 等于 b"
elif [ $a -gt $b ]
then
   echo "a 大于 b"
elif [ $a -lt $b ]
then
   echo "a 小于 b"
else
   echo "没有符合的条件"
fi

result  --->   a 小于 b

num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
    echo '两个数字相等!'
else
    echo '两个数字不相等!'
fi


read age
if (( $age <= 2 )); then
    echo "婴儿"
elif (( $age >= 3 && $age <= 8 )); then
    echo "幼儿"
elif (( $age >= 9 && $age <= 17 )); then
    echo "少年"
elif (( $age >= 18 && $age <=25 )); then
    echo "成年"
elif (( $age >= 26 && $age <= 40 )); then
    echo "青年"
elif (( $age >= 41 && $age <= 60 )); then
    echo "中年"
else
    echo "老年"
fi

For循环

案例1:
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
案例2:
#!/bin/bash
for str in This is a string
do
    echo $str
done

输出结果:
This
is
a
string


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


while 语句

实例
#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done
运行脚本,输出:
1
2
3
4
5



echo '按下 <CTRL-D> 退出'
echo -n '输入你最喜欢的网站名: '
while read FILM
do
    echo "是的!$FILM 是一个好网站"
done


按下 <CTRL-D> 退出
输入你最喜欢的网站名:菜鸟教程
是的!菜鸟教程 是一个好网站

无限循环

while true
do
    command
done

while :
do
    command
done

CASE …ESAC等价于switch

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac


案例
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


#!/bin/sh

site="runoob"

case "$site" in
   "runoob") echo "菜鸟教程"
   ;;
   "google") echo "Google 搜索"
   ;;
   "taobao") echo "淘宝网"
   ;;
esac

跳出循环break continue

break命令

break命令允许跳出所有循环(终止执行后面的所有循环)。

下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。

#!/bin/bash
while :
do
    echo -n "输入 1 到 5 之间的数字:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
            break
        ;;
    esac
done

执行以上代码,输出结果为:

输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束

continue

continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

对上面的例子进行修改:

#!/bin/bash
while :
do
    echo -n "输入 1 到 5 之间的数字: "
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的!"
            continue
            echo "游戏结束"
        ;;
    esac
done

运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo “游戏结束” 永远不会被执行。

Shell 函数

[ function ] funname [()]

{
    action;
    [return int;]
}

function函数标识可以省略

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

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


结果:
这个函数会对输入的两个数字进行相加运算...
输入第一个数字: 
1
输入第二个数字: 
2
两个数字分别为 1 和 2 !
输入的两个数字之和为 3 !

函数参数

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

funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

输出结果:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !

字符串的连接和单引号双引号区别和字符串拼接

下面我们说一下三种形式的区别:

  1. 由单引号' '包围的字符串:
  • 任何字符都会原样输出,在其中使用变量是无效的。
  • 字符串中不能出现单引号,即使对单引号进行转义也不行。
  1. 由双引号" "包围的字符串:
  • 如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
  • 字符串中可以出现双引号,只要它被转义了就行。
  1. 不被引号包围的字符串
  • 不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。
  • 字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。

我们通过代码来演示一下三种形式的区别:

#!/bin/bash
n=74
str1=c.biancheng.net$n      #字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析
str2="shell \"script\" $n"  #字符串中可以出现双引号,只要它被转义了就行。
str3='C语言中文网 $n'        #原样输出 ,而且单引号内不能出现单引号
echo $str1
echo $str2
echo $str3

运行结果:

c.biancheng.net74
shell "script" 74
C语言中文网 $n

str1 中包含了$n,它被解析为变量 n 的引用。$n后边有空格,紧随空格的是 str2;Shell 将 str2 解释为一个新的变量名,而不是作为字符串 str1 的一部分。

str2 中包含了引号,但是被转义了(由反斜杠\开头的表示转义字符)。str2 中也包含了$n,它也被解析为变量 n 的引用。

str3 中也包含了$n,但是仅仅是作为普通字符,并没有解析为变量 n 的引用。

字符串拼接

然而,在 Shell 中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接,非常简单粗暴。请看下面的例子:
#!/bin/bash
name="Shell"
url="http://c.biancheng.net/shell/"
str1=$name$url  #中间不能有空格
str2="$name $url"  #如果被双引号包围,那么中间可以有空格
str3=$name": "$url  #中间可以出现别的字符串
str4="$name: $url"  #这样写也可以
str5="${name}Script: ${url}index.html"  #这个时候需要给变量名加上大括号
echo $str1
echo $str2
echo $str3
echo $str4
echo $str5

运行结果:

Shellhttp://c.biancheng.net/shell/
Shell http://c.biancheng.net/shell/
Shell: http://c.biancheng.net/shell/
Shell: http://c.biancheng.net/shell/
ShellScript: http://c.biancheng.net/shell/index.html

字符串的截取

格式说明
${string: start}从 string 字符串的左边第 start 个字符开始截取,直到最后。
url=“c.biancheng.net”
echo ${url: 2} #结果为biancheng.net。
${string: start :length}从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。索引从0开始
url=“c.biancheng.net”
echo ${url: 2: 9} #结果为biancheng
${string: 0-start :length}从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
url="c.biancheng.net"
echo ${url: 0-13: 9} #结果为biancheng。从右边数,b是第 13 个字符。
${string: 0-start}从 string 字符串的右边第 start 个字符开始截取,直到最后。后面数就从一开始数
url=“c.biancheng.net”
echo ${url: 0-13} #省略 length,直接截取到字符串末尾 结果为biancheng.net
${string#*chars}从 string 字符串第一次出现 *chars 的位置开始,截取 chars 右边的所有字符。
url="http://c.biancheng.net/index.html"
echo ${url#
:} #结果为//c.biancheng.net/index.htm
${string##*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string%*chars}从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
${string%%*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
${string##*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。


1. \#!/bin/bash
2. 
3. url="http://c.biancheng.net/index.html"
4. echo ${url#*/}    #结果为 /c.biancheng.net/index.html
5. echo ${url##*/}   #结果为 index.html
6. 
7. str="---aa+++aa@@@"
8. echo ${str#*aa}   #结果为 +++aa@@@
9. echo ${str##*aa}  #结果为 @@@

使用 % 截取左边字符
请注意*的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。其他方面%和#的用法相同,这里不再赘述,仅举例说明:

#!/bin/bash
url="http://c.biancheng.net/index.html"
echo ${url%/*}  #结果为 http://c.biancheng.net
echo ${url%%/*}  #结果为 http:
str="---aa+++aa@@@"
echo ${str%aa*}  #结果为 ---aa+++
echo ${str%%aa*}  #结果为 ---
1) 从字符串左边开始计数

如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:

${string: start :length}

其中,string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),

length 是要截取的长度(省略的话表示直到字符串的末尾)。

例如:

url="c.biancheng.net"
echo ${url: 2: 9}     #结果为`biancheng`。url="http://c.biancheng.net/index.html"
echo ${url#*/}    #结果为 /c.biancheng.net/index.html
echo ${url##*/}   #结果为 index.html
2) 从右边开始计数

如果想从字符串的右边开始计数,那么截取字符串的具体格式如下:

${string: 0-start :length}

同第 1) 种格式相比,第 2) 种格式仅仅多了0-,这是固定的写法,专门用来表示从字符串右边开始计数。

这里需要强调两点:

  • 从左边开始计数时,起始数字是 0(这符合程序员思维);从右边开始计数时,起始数字是 1(这符合常人思维)。计数方向不同,起始数字也不同。
  • 不管从哪边开始计数,截取方向都是从左到右。

例如:

url="c.biancheng.net"
echo ${url: 0-13: 9}

结果为biancheng。从右边数,b是第 13 个字符。

再如:

url="c.biancheng.net"
echo ${url: 0-13}  #省略 length,直接截取到字符串末尾

结果为biancheng.net

Shell alias:给命令创建别名

alisa 用来给命令创建一个别名。若直接输入该命令且不带任何参数,则列出当前 Shell 进程中使用了哪些别名。现在你应该能理解类似ll这样的命令为什么与ls -l的效果是一样的吧。

下面让我们来看一下有哪些命令被默认创建了别名:

[mozhiyan@localhost ~]$ alias
alias cp='cp -i'
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias ls='ls --color=tty'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'


alias new_name='command'
比如,一般的关机命令是shutdown-h now,写起来比较长,这时可以重新定义一个关机命令,以后就方便多了。
alias myShutdown='shutdown -h now'

再如,通过 date 命令可以获得当前的 UNIX 时间戳,具体写法为date +%s,如果你嫌弃它太长或者不容易记住,那可以给它定义一个别名。
alias timestamp='date +%s'

Shell read命令:读取从键盘输入的数据

a array把读取的数据赋值给数组 array,从下标 0 开始。
-d delimiter用字符串 delimiter 指定读取结束的位置,而不是一个换行符(读取到的数据不包括 delimiter)。
-e在获取用户输入的时候,对功能键进行编码转换,不会直接显式功能键对应的字符。
-n num读取 num 个字符,而不是整行字符。
-p prompt显示提示信息,提示内容为 prompt。
-r原样读取(Raw mode),不把反斜杠字符解释为转义字符。
-s静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的。
-t seconds设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个非 0 的退出状态,表示读取失败。
-u fd使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。

【实例1】使用 read 命令给多个变量赋值。

#!/bin/bash
read -p "Enter some information > " name url age  #-p prompt显示提示信息,提示内容为 prompt。
echo "网站名字:$name"
echo "网址:$url"
echo "年龄:$age"

运行结果:
Enter some information > C语言中文网 http://c.biancheng.net 7↙
网站名字:C语言中文网
网址:http://c.biancheng.net
年龄:7


read -n 1 -p "Enter a char > " char
printf "\n"  #换行
echo $char

运行结果:
Enter a char > 1
1

-n 1表示只读取一个字符。运行脚本后,只要用户输入一个字符,立即读取结束,不用等待用户按下回车键。

在指定时间内输入密码。

#!/bin/bash
if
    read -t 20 -sp "Enter password in 20 seconds(once) > " pass1 && printf "\n" &&  #第一次输入密码
    read -t 20 -sp "Enter password in 20 seconds(again)> " pass2 && printf "\n" &&  #第二次输入密码
    [ $pass1 == $pass2 ]  #判断两次输入的密码是否相等
then
    echo "Valid password"
else
    echo "Invalid password"
fi

这段代码中,我们使用&&组合了多个命令,这些命令会依次执行,并且从整体上作为 if 语句的判断条件,只要其中一个命令执行失败(退出状态为非 0 值),整个判断条件就失败了,后续的命令也就没有必要执行了。

如果两次输入密码相同,运行结果为:
Enter password in 20 seconds(once) >
Enter password in 20 seconds(again)>
Valid password

如果两次输入密码不同,运行结果为:
Enter password in 20 seconds(once) >
Enter password in 20 seconds(again)>
Invalid password

如果第一次输入超时,运行结果为:
Enter password in 20 seconds(once) > Invalid password

如果第二次输入超时,运行结果为:
Enter password in 20 seconds(once) >
Enter password in 20 seconds(again)> Invalid password

Shell (()):对整数进行数学运算

let语法和(())比较和区别

let命令和(())的语法类似:

echo let a+b #错误,echo会把 let a+b作为一个字符串输出    只能这样:echo((a+b))

i=2
echo let i+=8  #结果:10

Shell (( )) 的用法

双小括号 (( )) 的语法格式为:

((表达式))

通俗地讲,就是将数学运算表达式放在(())之间。

表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( )) 命令的执行结果。

可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。

运算操作符/运算命令说明
((a=10+66) ((b=a-15)) ((c=a+b))这种写法可以在计算完成后给变量赋值。以 ((b=a-15)) 为例,即将 a-15 的运算结果赋值给变量 c。 注意,使用变量时不用加$前缀,(( )) 会自动解析变量名。
a= ( ( 10 + 66 ) b = ((10+66) b= ((10+66)b=((a-15)) c=$((a+b))可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c= ( ( a + b ) ) 为 例 , 即 将 a + b 这 个 表 达 式 的 运 算 结 果 赋 值 给 变 量 c 。 注 意 , 类 似 c = ( ( a + b ) ) 这 样 的 写 法 是 错 误 的 , 不 加 ‘ ((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。 注意,类似 c=((a+b)) 这样的写法是错误的,不加` ((a+b))a+bcc=((a+b))`就不能取得表达式的结果。
((a>7 && b==c))(( )) 也可以进行逻辑运算,在 if 语句中常会使用逻辑运算。
echo $((a+10))需要立即输出表达式的运算结果时,可以在 (( )) 前面加$符号。
((a=3+5, b=a+10))对多个表达式同时进行计算。

在 (( )) 中使用变量无需加上$前缀,(( )) 会自动解析变量名,这使得代码更加简洁,也符合程序员的书写习惯。

Shell (( )) 实例演示

【实例1】利用 (( )) 进行简单的数值计算。

[c.biancheng.net]$ echo $((1+1))
2
[c.biancheng.net]$ echo $((6-3))
3
[c.biancheng.net]$ i=5
[c.biancheng.net]$ ((i=i*2))  #可以简写为 ((i*=2))。
[c.biancheng.net]$ echo $i   #使用 echo 输出变量结果时要加 $。
10

【实例2】用 (( )) 进行稍微复杂一些的综合算术运算。

[c.biancheng.net]$ ((a=1+2**3-4%3))
[c.biancheng.net]$ echo $a
8
[c.biancheng.net]$ b=$((1+2**3-4%3)) #运算后将结果赋值给变量,变量放在了括号的外面。
[c.biancheng.net]$ echo $b
8
[c.biancheng.net]$ echo $((1+2**3-4%3)) #也可以直接将表达式的结果输出,注意不要丢掉 $ 符号。
8
[c.biancheng.net]$ a=$((100*(100+1)/2)) #利用公式计算1+2+3+...+100的和。
[c.biancheng.net]$ echo $a
5050
[c.biancheng.net]$ echo $((100*(100+1)/2)) #也可以直接输出表达式的结果。
5050

【实例3】利用 (( )) 进行逻辑运算。

[c.biancheng.net]$ echo $((3<8))  #3<8 的结果是成立的,因此,输出了 1,1 表示真
1
[c.biancheng.net]$ echo $((8<3))  #8<3 的结果是不成立的,因此,输出了 0,0 表示假。
0
[c.biancheng.net]$ echo $((8==8)) #判断是否相等。
1
[c.biancheng.net]$ if ((8>7&&5==5))
> then
> echo yes
> fi
yes

最后是一个简单的 if 语句的格式,它的意思是,如果 8>7 成立,并且 5==5 成立,那么输出 yes。显然,这两个条件都是成立的,所以输出了 yes。

【实例4】利用 (( )) 进行自增(++)和自减(–)运算。

[c.biancheng.net]$ a=10
[c.biancheng.net]$ echo $((a++))  #如果++在a的后面,那么在输出整个表达式时,会输出a的值,因为a为10,所以表达式的值为10。
10
[c.biancheng.net]$ echo $a #执行上面的表达式后,因为有a++,因此a会自增1,因此输出a的值为11。
11
[c.biancheng.net]$ a=11
[c.biancheng.net]$ echo $((a--)) #如果--在a的后面,那么在输出整个表达式时,会输出a的值,因为a为11,所以表达式的值的为11。
11
[c.biancheng.net]$ echo $a #执行上面的表达式后,因为有a--,因此a会自动减1,因此a为10。
10
[c.biancheng.net]$ a=10
[c.biancheng.net]$ echo $((--a))  #如果--在a的前面,那么在输出整个表达式时,先进行自增或自减计算,因为a为10,且要自减,所以表达式的值为9。
9
[c.biancheng.net]$ echo $a #执行上面的表达式后,a自减1,因此a为9。
9
[c.biancheng.net]$ echo $((++a))  #如果++在a的前面,输出整个表达式时,先进行自增或自减计算,因为a为9,且要自增1,所以输出10。
10
[c.biancheng.net]$ echo $a  #执行上面的表达式后,a自增1,因此a为10。
10

本教程假设读者具备基本的编程能力,相信读者对于前自增(前自减)和后自增(后自减)的区别也非常清楚,这里就不再赘述,只进行简单的说明:

  • 执行 echo $((a++)) 和 echo $((a–)) 命令输出整个表达式时,输出的值即为 a 的值,表达式执行完毕后,会再对 a 进行 ++、-- 的运算;
  • 而执行 echo $((++a)) 和 echo $((–a)) 命令输出整个表达式时,会先对 a 进行 ++、-- 的运算,然后再输出表达式的值,即为 a 运算后的值。

【实例5】利用 (( )) 同时对多个表达式进行计算。

[c.biancheng.net]$ ((a=3+5, b=a+10))  #先计算第一个表达式,再计算第二个表达式
[c.biancheng.net]$ echo $a $b
8 18
[c.biancheng.net]$ c=$((4+8, a+b))  #以最后一个表达式的结果作为整个(())命令的执行结果
[c.biancheng.net]$ echo $c
26

学习目标:

提示:这里可以添加学习目标
例如:一周掌握 Java 入门知识


学习内容:

提示:这里可以添加要学的内容
例如:
1、 搭建 Java 开发环境
2、 掌握 Java 基本语法
3、 掌握条件语句
4、 掌握循环语句


学习时间:

提示:这里可以添加计划学习的时间
例如:
1、 周一至周五晚上 7 点—晚上9点
2、 周六上午 9 点-上午 11 点
3、 周日下午 3 点-下午 6 点


学习产出:

提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值