Shell命令学习记录

先学习记录,待整理。。

1. 一分钟实现一个最简单的Shell脚本

1.1 创建文件

打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell)

1.2 编辑内容并保存
#!/bin/bash
echo "Hello World !"

解释:

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell

echo 命令用于向窗口输出文本

1.3 运行Shell脚本
  • 作为可执行程序

    cd到相应目录:

    chmod +x ./test.sh  #使脚本具有执行权限
    ./test.sh  #执行脚本
    
  • 作为解释器参数

    /bin/sh test.sh #直接运行解释器,其参数就是 shell 脚本的文件名
    
1.4 注释
  • 单行注释

    使用#

    #这是一行注释
    
  • 多行注释

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

2. 变量

2.1 变量的使用
2.1.1 创建变量
your_name="runoob.com"

注意:变量名和等号之间不能有空格,注意命名规则

2.1.2 使用变量

使用变量的时候需要加$

your_name="qinjx"
echo $your_name   #输出变量your_name的值
echo ${your_name} #输出变量your_name的值

加{}是为了方便区别下面循环场景:

for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done
2.1.3 只读变量
#!/bin/bash
myUrl="https://www.google.com"
readonly myUrl
myUrl="https://www.runoob.com"

这样会报错,myUrl为只读的

2.1.4 删除变量
#!/bin/sh
myUrl="https://www.runoob.com"
unset myUrl
echo $myUrl

以上实例执行将没有任何输出。

2.1.5 变量类型

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

  • 1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  • 2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • 3) shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
2.2 字符串
2.2.1 单引号和双引号
  • 单引号

    • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;

      #下面这样是不对的
      str='123'
      echo 'aaa is $str'
      
    • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

  • 双引号

    • 双引号里可以有变量

      #下面这样是可以的
      str='123'
      echo "aaa is $str"
      
    • 双引号里可以出现转义字符

2.2.2 拼接字符串
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

输出结果为:

hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !
2.2.3 获取字符串长度
string="abcd"
echo ${#string} #输出 4
2.2.4 字符串截取
string="runoob is a great site"
echo ${string:1:4} # 输出 unoo

3. 参数传递

相关命令记录:

$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。 如"1 n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与@"用「"」括起来的情况、以"2" … "$n" 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#传递参数示例
$ chmod +x test.sh 
$ ./test.sh 1 2 3

上面是运行脚本test.sh,并且传递了3个参数。

3.1 参数的获取

脚本内获取参数的格式为:$nn 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数...

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
3.2 补充

@ 区别:

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

4. 数组

Bash Shell 只支持一维数组(不支持多维数组)

比如:

array_name=(value1 value2 ... valuen)

示例:

my_array=(A B "C" D)

#也可以使用下标来定义数组:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
4.1 读取数组
${array_name[index]}

示例:

my_array=(A B "C" D)

echo "第一个元素为: ${my_array[0]}"
echo "第二个元素为: ${my_array[1]}"
echo "第三个元素为: ${my_array[2]}"
echo "第四个元素为: ${my_array[3]}"
4.2 获取数组中所有元素
my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D

echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"

#输出结果:
数组的元素为: A B C D
数组的元素为: A B C D
4.3 获取数组长度

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

my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D

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

#输出结果:
数组元素个数为: 4
数组元素个数为: 4

5. 运算符

5.1 算术运算符
运算符 说明 举例
+ 加法 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。 [ b ] 返回 false。
!= 不相等。用于比较两个数字,不相同则返回 true。 [ b ] 返回 true。

注意:

  1. 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2
  2. 条件表达式要放在方括号之间,并且要有空格,例如: [b] 是错误的,必须写成 [ b ]
  3. 注意使用的是反引号 ` 而不是单引号 '

举例:

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

注意:

  • 乘号(*)前边必须加反斜杠()才能实现乘法运算;
  • if...then...fi 是条件语句
  • 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 ""
5.2 关系运算符
运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ b ] 返回 false。
-ne 检测两个数是否不相等,不相等返回 true。 [ b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ b ] 返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ b ] 返回 true。

注意:

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

5.3 布尔运算符
运算符 说明 举例
! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
-o 或运算,有一个表达式为 true 则返回 true。 [ b -gt 100 ] 返回 true。
-a 与运算,两个表达式都为 true 才返回 true。 [ b -gt 100 ] 返回 false。
5.4 逻辑运算符
运算符 说明 举例
&& 逻辑的 AND [[ b -gt 100 ]] 返回 false
|| 逻辑的 OR [[ b -gt 100 ]] 返回 true
5.5 字符串运算符
运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。 [ b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否不为 0,不为 0 返回 true。 [ -n "$a" ] 返回 true。
$ 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。
5.6 文件测试运算符
操作符 说明 举例
-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。

示例:

if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

6. echo

  • 显示普通字符串

    echo "It is a test"
    
  • 显示转义字符

    echo "\"It is a test\""
    
    # 输出结果:
    "It is a test"
    
  • 显示变量

    read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

    #!/bin/sh
    read name 
    echo "$name It is a test"
    
    # 以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:
    # sh test.sh
    OK                     #标准输入
    OK It is a test        #输出
    
  • 显示换行

    echo -e "OK! \n" # -e 开启转义
    echo "It is a test"
    # 输出结果:
    OK!
    
    It is a test
    
  • 显示不换行

    #!/bin/sh
    echo -e "OK! \c" # -e 开启转义 \c 不换行
    echo "It is a test"
    
    # 输出结果:
    OK! It is a test
    
  • 显示结果定向至文件

    echo "It is a test" > myfile
    
  • 原样输出字符串,不进行转义或者取变量

    echo '$name\"'
    # 输出结果:
    $name\"
    
  • 显示命令执行结果

    # 这里使用的是反引号 `, 而不是单引号 '。
    echo `date`
    # 输出结果:
    2020年 9月 7日 星期一 16时33分53秒 CST
    

7.printf命令

  • 移植性比echo好
  • 不会像echo默认加换行符,可以手动加\n

printf 命令的语法:

printf  format-string  [arguments...]
#format-string: 为格式控制字符串
#arguments: 为参数列表。

举例1:

#!/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都是格式替代符

%-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

8. test命令

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

8.1 数值测试
参数 说明
-eq 等于则为真
-ne 不等于则为真
-gt 大于则为真
-ge 大于等于则为真
-lt 小于则为真
-le 小于等于则为真

示例:

num1=100
num2=100
if test $[num1] -eq $[num2]
then
    echo '两个数相等!'
else
    echo '两个数不相等!'
fi

代码中的 [] 执行基本的算数运算,比如:

#!/bin/bash

a=5
b=6

result=$[a+b] # 注意等号两边不能有空格
echo "result 为: $result"
8.2 字符串测试
参数 说明
= 等于则为真
!= 不相等则为真
-z 字符串 字符串的长度为零则为真
-n 字符串 字符串的长度不为零则为真

示例:

num1="ru1noob"
num2="runoob"
if test $num1 = $num2
then
    echo '两个字符串相等!'
else
    echo '两个字符串不相等!'
fi
8.3 文件测试
参数 说明
-e 文件名 如果文件存在则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-d 文件名 如果文件存在且为目录则为真
-f 文件名 如果文件存在且为普通文件则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真

示例:

cd /bin
if test -e ./bash
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi

另外,Shell 还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低。例如:

cd /bin
if test -e ./notFile -o -e ./bash
then
    echo '至少有一个文件存在!'
else
    echo '两个文件都不存在'
fi

9. 流程控制

在sh/bash里如果else分支没有语句执行,就不要写这个else。

9.1 if else
if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi #末尾的fi就是if倒过来拼写
9.2 if else-if else
if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi
9.3 for 循环

当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done
9.4 while
while condition
do
    command
done
9.5 无限循环
while true
do
    command
done
until 循环

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

until 循环与 while 循环在处理方式上刚好相反。

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

until 语法格式:

until condition
do
    command
done
9.7 case
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

10. 函数

函数定义如下:

[ function ] funname [()]

{

    action;

    [return int;]

}
10.1 不带参数和返回值得函数
demoFun(){
    echo "这是我的第一个 shell 函数!"
}
echo "-----函数开始执行-----"
demoFun
echo "-----函数执行完毕-----"
10.2 带return语句的函数
funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "输入第二个数字: "
    read anotherNum
    echo "两个数字分别为 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

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

函数返回值在调用该函数后通过 $? 来获得。

注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

10.3 函数参数

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 1表示第一个参数,$2表示第二个参数...

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 !

注意,{10}。当n>=10时,需要使用${n}来获取参数。

用来处理参数的特殊字符:

参数处理 说明
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
11. 输入/输出重定向
命令 说明
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。

需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。

11.1 输出重定向
command1 > file1 #表示执行command1然后将输出的内容存入file1,注意任何file1内的已经存在的内容将被新内容替代。如果要将新内容添加在文件末尾,请使用>>操作符。

示例:

echo "测试文本内容" > aa.txt

执行后并没有在终端输出信息,会将who命令的结果输入到aa.txt文件中,并且会覆盖原有内容,如果想在原有内容之后追加,可以使用>>

echo "追加测试文本" >> aa.txt
11.2 输入重定向

和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:

command1 < file1

你可能感兴趣的:(Shell命令学习记录)