shell 脚本常用语法

8,711 阅读6分钟

1.概述

1.1 Linux提供的Shell解析器有:

[root@hadoop1 /]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash

1.2 bash和sh的关系

[root@hadoop1 /]# ll /bin/ | grep bash
-rwxr-xr-x  1 root root     964600 8   8 2019 bash
lrwxrwxrwx  1 root root          4 4  27 2020 sh -> bash

1.3 Centos默认的解析器是bash

[root@hadoop1 /]# echo $SHELL
/bin/bash

2.脚本入门

2.1 脚本格式

脚本以#!/bin/bash开头(指定解析器)

#!/bin/bash
xxxxxxxxxx脚本内容

2.2 helloworld

#!/bin/bash

echo 'helloworld'

2.3 执行脚本

bash执行

[root@hadoop1 shell]# bash hello.sh 
helloworld

sh执行

[root@hadoop1 shell]# sh hello.sh 
helloworld

直接执行(需要有执行权限)

[root@hadoop1 shell]# chmod 744 hello.sh 
[root@hadoop1 shell]# ./hello.sh 
helloworld

3.变量

3.1 系统预定义变量

1. 常用系统变量

HOMEHOME、PWD、SHELLSHELL、USER等

2. 案例实操

查看系统变量的值
[root@hadoop1 shell]# echo $SHELL
/bin/bash

显示当前Shell中所有变量:set
[root@hadoop1 shell]# set
BASH=/usr/bin/bash
BASH_ALIASES=()

3.2 自定义变量

1. 基本语法

1. 定义变量:变量=值 
2. 撤销变量:unset 变量
3. 声明静态变量:readonly变量  (注意:不能unset)
4. 提升为全局环境变量: export 变量名 (可供其他Shell程序使用)

2. 变量定义规则

1. 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
2. 等号两侧不能有空格
3. 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
4. 变量的值如果有空格,需要使用双引号或单引号括起来。
[root@hadoop1 shell]# aaa=123
[root@hadoop1 shell]# echo $aaa
123
[root@hadoop1 shell]# unset aaa
[root@hadoop1 shell]# echo $aaa

[root@hadoop1 shell]# bbb=234
[root@hadoop1 shell]# readonly bbb
[root@hadoop1 shell]# echo $bbb
234
[root@hadoop1 shell]# unset bbb
bash: unset: bbb: 无法反设定: 只读 variable
[root@hadoop1 shell]# aa="大 数 据"
[root@hadoop1 shell]# export aa
[root@hadoop1 shell]# echo aa
aa

3.3 特殊变量

1. $n

功能描述:n为数字,0代表该脚本名称,0代表该脚本名称,1-9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如{10}

#!/bin/bash

echo $0 $1 $2
[root@hadoop1 shell]# sh bianliang.sh 1 2
bianliang.sh 1 2

2. $#

功能描述:获取所有输入参数个数,常用于循环

#!/bin/bash

echo $#
[root@hadoop1 shell]# sh bianliang.sh 1 2
2

3. *、@

  • (功能描述:这个变量代表命令行中所有的参数,* (功能描述:这个变量代表命令行中所有的参数,*把所有的参数看成一个整体)
  • @(功能描述:这个变量也代表命令行中所有的参数,不过@ (功能描述:这个变量也代表命令行中所有的参数,不过@把每个参数区分对待)
#!/bin/bash

echo $*
echo $@

再循环中 可以发现区别

[root@hadoop1 shell]# sh bianliang.sh 1 2
1 2
1 2

4. $?

功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了

[root@hadoop1 shell]# ll
总用量 8
-rw-r--r-- 1 root root 53 49 19:19 bianliang.sh
-rwxr--r-- 1 root root 31 49 18:39 hello.sh
[root@hadoop1 shell]# echo $?
0
[root@hadoop1 shell]# lllll
bash: lllll: 未找到命令
[root@hadoop1 shell]# echo $?
127

4.运算符

  1. $((运算式))
  2. $[运算式]
[root@hadoop1 shell]# echo "$((2+3))"
5
[root@hadoop1 shell]# echo "$[3+3]"
6

5.条件判断

  1. 基本语法

    • test condition
    • [ condition ](注意condition前后要有空格)
  2. 判断条件

两个整数之间比较

符号作用
==字符串比较
-lt小于(less than)
-le小于等于(less equal)
-eq等于(equal)
-gt大于(greater than)
-ge大于等于(greater equal)
-ne不等于(Not equal)

按照文件权限进行判断

符号作用
-r有读的权限(read)
-w有写的权限(write)
-x有执行的权限(execute)

按照文件类型进行判断

符号作用
-f文件存在并且是一个常规的文件(file)
-e文件存在(existence)
-d文件存在并是一个目录(directory)
[root@hadoop1 shell]# test 1 -lt 2
[root@hadoop1 shell]# echo $?
0
[root@hadoop1 shell]# test 1 -gt 2
[root@hadoop1 shell]# echo $?
1

[root@hadoop1 shell]# ll
总用量 8
-rw-r--r-- 1 root root 53 49 19:19 bianliang.sh
-rwxr--r-- 1 root root 31 49 18:39 hello.sh
[root@hadoop1 shell]# [ -x bianliang.sh ]
[root@hadoop1 shell]# echo $?
1
[root@hadoop1 shell]# [ -x hello.sh ]
[root@hadoop1 shell]# echo $?
0

[root@hadoop1 shell]# [ -f hello.sh ]
[root@hadoop1 shell]# echo $?
0
[root@hadoop1 shell]# [ -d hello.sh ]
[root@hadoop1 shell]# echo $?
1

6.流程控制

6.1 if 判断

基本语法:

if [ condition ]; then
     # if body
elif [ condition ]; then
     # else if body
else
     # else body
fi

脚步:

#!/bin/bash

if [ $1 -eq 1 ]; then
     echo "$1=1"
elif [ $1 -lt 1 ]; then
     echo "$1<1"
else
     echo "$1>1"
fi

执行结果:

[root@hadoop1 shell]# sh if.sh 1
1=1
[root@hadoop1 shell]# sh if.sh 2
2>1
[root@hadoop1 shell]# sh if.sh 0
0<1

6.2 case语句

基本语法:

case "${item}" in
    1)
        echo "item = 1"
    ;;
    2|3)
        echo "item = 2 or item = 3"
    ;;
    *)
        echo "default (none of above)"
    ;;
esac

脚步:

#!/bin/bash

case "${1}" in
    1)
        echo "param = 1"
    ;;
    2|3)
        echo "param = 2 or param = 3"
    ;;
    *)
        echo "default (none of above)"
    ;;
esac

执行结果:

[root@hadoop1 shell]# sh case.sh 1
param = 1
[root@hadoop1 shell]# sh case.sh 2
param = 2 or param = 3
[root@hadoop1 shell]# sh case.sh 3
param = 2 or param = 3
[root@hadoop1 shell]# sh case.sh 4
default (none of above)

6.3 for循环

基本语法:

for((i=0;i<n;i++)); do
    echo "${i}"
done

for item in {a..z}; do
    echo "${item}"
done

脚步:

#!/bin/bash


for((i=0;i<$1;i++)); do
    echo "${i}"
done

for item in {1,2,3}; do
    echo "${item}"
done

执行结果:

[root@hadoop1 shell]# sh for.sh 3
0
1
2
1
2
3

6.4 while循环

基本语法:

while [ condition ]; do
    # body
done

脚步:

#!/bin/bash

i=0
while [ $i -lt $1 ]; do
    # body
    echo "${i}"
    i=$[$i+1]
done

执行结果:

[root@hadoop1 shell]# sh while.sh 2
0
1

7.read读取控制台输入

基本语法:

  • read(选项)(参数)

选项:

  • -p:指定读取值时的提示符;
  • -t:指定读取值时等待的时间(秒)

参数:

  • 变量:指定读取值的变量名
[root@hadoop1 shell]# read -t 5 -p "5秒内输入名字:" name
5秒内输入名字:root
[root@hadoop1 shell]# echo $name
root

8函数

8.1 系统函数

basename

基本语法: basename [string / pathname] [suffix]
功能描述:basename命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来
选项:suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。

[root@hadoop1 shell]# basename /opt/1.txt
1.txt
[root@hadoop1 shell]# basename /opt/test/
test

dirname

基本语法: dirname 文件绝对路径
功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)

[root@hadoop1 shell]# dirname /opt/1.txt
/opt
[root@hadoop1 shell]# dirname /opt/test/
/opt

8.2 自定义函数

基本语法:

[ function ] funname[()]{
	Action;
	[return int;]
}

function funname(){
	Action;
	return int;
}

funname(){
	Action;
	return int;
}

代码:

#!/bin/bash

function funname(){
	echo “2”
}

funname

执行结果:

[root@hadoop1 shell]# sh function.sh 2

9. Shell工具

9.1 cut

基本用法
cut [选项参数] filename
说明:默认分隔符是制表符

选项参数说明

选项参数功能
-f列号,提取第几列
-d分隔符,按照指定分隔符分割列
-c指定具体的字符
-f 1,7  表示第一和第七列
[root@hadoop1 test]# cut /etc/passwd -d ":" -f 1,7
root:/bin/bash
bin:/sbin/nologin
daemon:/sbin/nologin

-f 3-  第三列之后都要
[root@hadoop1 test]# cut /etc/passwd -d ":" -f 3-
0:0:root:/root:/bin/bash
1:1:bin:/bin:/sbin/nologin
2:2:daemon:/sbin:/sbin/nologi

9.2 awk

基本用法
awk [选项参数] ‘pattern1{action1} pattern2{action2}...’ filename
pattern:表示AWK在数据中查找的内容,就是匹配模式
action:在找到匹配内容时所执行的一系列命令

选项参数说明

选项参数功能
-F指定输入文件折分隔符
-v赋值一个用户定义变量

awk的内置变量

变量说明
FILENAME文件名
NR已读的记录数(行数)
NF浏览记录的域的个数(切割后,列的个数)
[root@hadoop1 test]# awk -F ":" '{print $1" "$3}' /etc/passwd
root 0
bin 1

$3+1 第三列 加1
[root@hadoop1 test]# awk -F ":" '{print $1" "$3+1}' /etc/passwd
root 1
bin 2

-v i=2      $3+i    使用变量方式加2
[root@hadoop1 test]# awk -v i=2 -F ":" '{print $1" "$3+i}' /etc/passwd
root 2
bin 3

/^r/{print $1" "$3+i} 使用正则表达式过滤
[root@hadoop1 test]# awk -v i=2 -F ":" '/^r/{print $1" "$3+i}' /etc/passwd
root 2

使用 BRGINEND 在首尾行加文本
[root@hadoop1 test]# awk -v i=2 -F ":" 'BEGIN{print "begin"} {print $1" "$3+i} END{print "end"}' /etc/passwd
begin
root 2
bin 3
end

内置变量
[root@hadoop1 test]# awk -F ":" '{print FILENAME " "NR " "NF}' /etc/passwd
/etc/passwd 1 7
/etc/passwd 2 7

9.3 sort

基本语法
sort(选项)(参数)

选项说明
-n依照数值的大小排序
-r以相反的顺序来排序
-t设置排序时所用的分隔字符
-k指定需要排序的列
: 分割  按第三列 倒排 
[root@hadoop1 test]# sort -t ":" -nrk 3 /etc/passwd
test123:x:1003:1001::/home/test123:/bin/bash
test2:x:1002:1002::/home/test2:/bin/bash
test1:x:1001:1001::/home/test1:/bin/bash

10. 正则表达式入门

正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。在Linux中,grep,sed,awk等命令都支持通过正则表达式进行模式匹配。

10.1 常规匹配

一串不包含特殊字符的正则表达式匹配它自己,例如: [atguigu@hadoop102 datas]$ cat /etc/passwd | grep atguigu 就会匹配所有包含atguigu的行

10.2 常用特殊字符

  1. 特殊字符:^
^ 匹配一行的开头,例如:

[root@hadoop1 shell]# cat /etc/passwd | grep ^ro
root:x:0:0:root:/root:/bin/bash

会匹配出所有以 ro 开头的行
  1. 特殊字符:$
$ 匹配一行的结束,例如

[root@hadoop1 shell]# cat /etc/passwd | grep t$t
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

会匹配出所有以 t 结尾的行
思考:^$ 匹配什么?


  1. 特殊字符:.
. 匹配一个任意的字符,例如

[root@hadoop1 shell]# cat for.sh | grep i.+
for((i=0;i<$1;i++)); do

会匹配包含 i++ 等的所有行
  1. 特殊字符:*
* 不单独使用,他和左边第一个字符连用,表示匹配上一个字符0次或多次,例如

[root@hadoop1 shell]# cat for.sh | grep i*o
for((i=0;i<$1;i++)); do
    echo "${i}"
done

会匹配 io, iooo, ioooooo 等所有行
思考:.* 匹配什么?

  1. 特殊字符:[ ]
[ ] 表示匹配某个范围内的一个字符,例如
[6,8]------匹配6或者8
[a-z]------匹配一个a-z之间的字符
[a-z]*-----匹配任意字母字符串
[a-c, e-f]-匹配a-c或者e-f之间的任意字符


  1. 特殊字符:\
\ 表示转义,并不会单独使用。由于所有特殊字符都有其特定匹配模式,当我们想匹配某一特殊字符本身时(例如,我想找出所有包含 '$' 的行),就会碰到困难。此时我们就要将转义字符和特殊字符连用,来表示特殊字符本身,例如

注意:直接匹配 字符,需要进行转义并且加上单引号就会匹配所有包含a 字符,需要进行转义并且加上单引号就会匹配所有包含 ab 的行。