Shell编程

简介: Shell编程

@[toc]
  
  
  

  

Shell脚本入门

  

  

(1) 脚本格式:

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


练习:
创建一个Shell脚本,输出 hello world

PS:vim功能很强大,如果有文件就直接打开,如果没文件就创建并打开。

终端输入:

[root@hadoop100 scripts]# vim hello.sh

按i进入编辑模式,文件里输入:

#!/bin/bash
echo "hello world"

按Esc退出编辑模式,按 :wq 保存并退出。

  

(2) 脚本执行:

  • 第一种:采用 bashsh +脚本的相对路径或绝对路径 (不用赋予脚本 +x 权限)

  bash+脚本的相对路径:

[root@hadoop100 scripts]# bash hello.sh
hello,world

  bash+脚本的绝对路径:

[root@hadoop100 scripts]# bash /root/scripts/hello.sh
hello,world

  sh+脚本的相对路径:

[root@hadoop100 scripts]# sh hello.sh
hello,world

  sh+脚本的绝对路径:

[root@hadoop100 scripts]# sh /root/scripts/hello.sh
hello,world

  • 第二种:直接输入脚本的绝对路径或相对路径(必须赋予脚本 +x 可执行权限)

PS:r是读权限,w是写权限,x是可执行权限。一般刚创建的文件只有rw权限,没有x权限,x权限那里是个 -

  ①首先要赋予脚本 +x 权限

[root@hadoop100 scripts]# chmod +x hello.sh

  ②执行脚本

  相对路径

[root@hadoop100 scripts]# ./hello.sh
hello,world

  绝对路径:

[root@hadoop100 scripts]# /root/scripts/hello.sh
hello,world


知识拓展:

  1. 这两种方法都是在当前 shell 中打开一个子 shell 来执行脚本内容,当脚本内容结束,则子 shell关闭,回到父 shell 中。(存在环境变量继承问题:如在子 shell 中设置的当前变量,父 shell 是不可见的)
  2. 第一种执行方法本质是bash解析器执行脚本,所以脚本本身不需要执行权限。第二种执行方法本质是脚本需要自己执行,所以需要执行权限。
  3. pwd 查看目录 ; mkdir 创建文件夹 ; touch 新建文件 ; cat 查看内容

  
  
  

  

变量

  

  

一、系统预定义变量

  
(1) 常用的系统变量:

$HOME(当前主目录)、$PWD(当前工作目录目录)、$SHELL(当前使用的shell解析器)、$USER(当前用户)等。

  
(2) 练习:

[root@hadoop100 scripts]# echo $HOME
/root
[root@hadoop100 scripts]# echo $PWD
/root/scripts
[root@hadoop100 scripts]# echo $SHELL
/bin/bash
[root@hadoop100 scripts]# echo $USER
root

[root@hadoop100 scripts]# ls $HOME
initial-setup-ks.cfg scripts 公共 模板 视频 图片 文档 下载 音乐 桌面

  

二、自定义变量

  
(1) 基本语法:

  1. 定义变量: 变量名=变量值 (注意:=号前后都不能有空格!!!)
  2. 撤销变量: unset 变量名
  3. 声明静态变量: readonly 变量 (注意:不能 unset)
  4. 声明全局变量: export 变量

  
(2) 变量定义规则:

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

  
(3) 练习:

[root@hadoop100 scripts]# a=10
[root@hadoop100 scripts]# echo $a
10
[root@hadoop100 scripts]# unset a
[root@hadoop100 scripts]# echo $a

unset后,echo就打印空白一行了。

  

三、特殊变量

  

1、 $n

  
(1) 基本语法:

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

  
(2) 练习:

!#/bin/bash
echo '=================$n==================='
echo script name: $0
echo 1st parameter: $1
echo 2nd parameter: $2
[root@hadoop100 scripts]# ./parameter.sh abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$n===================
script name: ./parameter.sh
1st parameter: abc
2nd parameter: def

  

2、 $

  
(1) 基本语法:

  $# —— 参数个数统计变量
功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性。

  
(2) 练习:

!#/bin/bash
echo '=================$n==================='
echo script name: $0
echo 1st parameter: $1
echo 2nd parameter: $2
echo '=================$#==================='
echo parameter numbers: $#
[root@hadoop100 scripts]# ./parameter.sh abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$n\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=
script name: ./parameter.sh
1st parameter: abc
2nd parameter: def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=
parameter numbers: 2

  

3、 $*、$@

  
(1) 基本语法:

  $* —— 获取当前命令行提供的所有参数
功能描述:获取当前命令行提供的所有参数,$*把所有参数看成一个整体。

  $@ —— 获取当前命令行提供的所有参数
功能描述:获取当前命令行提供的所有参数,$@把每个参数区分对待。

  
(2) 练习:

!#/bin/bash
echo '=================$n==================='
echo script name: $0
echo 1st parameter: $1
echo 2nd parameter: $2
echo '=================$#==================='
echo parameter numbers: $#
echo '=================$*==================='
echo $*
echo '=================$@==================='
echo $@
[root@hadoop100 scripts]# ./parameter.sh abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$n\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\
script name: ./parameter.sh
1st parameter: abc
2nd parameter: def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\
parameter numbers: 2
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$*===================
abc def
\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=$@===================
abc def

区别在循环中可以看到。

  

4、 $?

  
(1) 基本语法:

  $? —— 整个脚本的返回值
功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己决定,但有个范围:0~255),则证明上一个命令执行不正确了(如果用在函数里也可以表示函数的返回值,但要注意范围)。

  
(2) 练习:

[root@hadoop100 scripts]# ./hello.sh
hello,world
[root@hadoop100 scripts]# echo $?
0

  
  
  

  

运算符

  

  
(1) 基本语法:

   $((运算式))$[运算式]

  
(2) 练习:

[root@hadoop100 scripts]# echo $((5+2))
7
[root@hadoop100 scripts]# echo $[5*2]
10

[root@hadoop100 scripts]# a=$[(2+3)*4]
[root@hadoop100 scripts]# echo $a
20

  
(3) 进阶练习:

编写个两数相加的文件

#!/bin/bash
sum=$[$1+$2]
echo sum=$sum
[root@hadoop100 scripts]# ./add.sh 25 90
sum=115

  
  
  

  

条件判断

  

  
(1) 基本语法:

有两种判断方法:

  • test 条件判断
  • [ 条件判断 ]   (注意 条件判断 前后都要有空格

PS:进行条件判断后,想看结果是真还是假,就要用 $? 接受返回值,即输入 echo $? 命令打印返回值结果。条件为真是0,条件为假是1 。

  

(2) 常用判断条件:

  1. 两个整数之间比较
符号 含义
-eq 等于(equal)
-ne 不等于(not equal)
-lt 小于(less than)
-gt 大于(greater than)
-le 小于等于(less equal)
-ge 大于等于(greater equal)

注:如果是字符串之间的比较,用等号 = 判断相等;用 != 判断不等。

  1. 按照文件权限进行判断
符号 含义
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)

  1. 按照文件类型进行判断
符号 含义
-e 文件存在(existence)
-f 文件存在并且是一个常规的文件(file)
-d 文件存在并且是一个目录(directory)

  
(3) 多条件判断:

  • && :逻辑与。表示前一条命令执行成功时,才执行后一条命令。
  • || :逻辑或。表示上一条命令执行失败后,才执行下一条命令。

两者结合可实现三元运算符。

  
(4) 练习:

[root@hadoop100 ~]# a=hello
[root@hadoop100 ~]# test $a = hello
[root@hadoop100 ~]# echo $?
0
[root@hadoop100 ~]# test $a = Hello
[root@hadoop100 ~]# echo $?
1

[root@hadoop100 ~]# [ 2 -lt 8 ]
[root@hadoop100 ~]# echo $?
0
[root@hadoop100 ~]# [ 2 -gt 8 ]
[root@hadoop100 ~]# echo $?
1

[root@hadoop100 ~]# cd scripts/
[root@hadoop100 scripts]# ls
add.sh cmd_test.sh fun_test.sh if_elif_else_test2.sh if_test.sh parameter.sh while_test.sh
case_test.sh for_test.sh hello.sh if_elif_else_test.sh parameter_for_test.sh read_test.sh
[root@hadoop100 scripts]# [ -x hello.sh ]
[root@hadoop100 scripts]# echo $?
0

[root@hadoop100 scripts]# [ -e hello.sh ]
[root@hadoop100 scripts]# echo $?
0

[root@hadoop100 scripts]# a=15
[root@hadoop100 scripts]# [ $a -lt 20 ] && echo "a比较小" || echo "a比较大"
a比较小
[root@hadoop100 scripts]# a=25
[root@hadoop100 scripts]# [ $a -lt 20 ] && echo "a比较小" || echo "a比较大"
a比较大

返回值为真,执行 || 前面的;返回值为假,执行 || 后面的。

  
  
  

  

流程控制

  

  

if 判断

  

(1) 基本语法:
  

  1. 单分支
if [ 条件判断式 ]
then
    程序
fi

或者

if [ 条件判断式 ];then
    程序
fi

  

  1. 多分支
if [ 条件判断式 ]
then
    程序
elif [ 条件判断式 ]
then
    程序
else
    程序
fi

  
注意事项:

  1. [ 条件判断式 ],中括号和条件判断式之间必须有空格。
  2. if后要有空格

  

(2) 练习:

#!/bin/bash

if [ "$1"x = "hello"x ]
then
        echo hello,world
fi
[root@hadoop100 scripts]# ./if_test.sh hello
hello,world

[root@hadoop100 scripts]# echo $a
25
[root@hadoop100 scripts]# if [ $a -gt 18 ] && [ $a -lt 35 ]; then echo 青年人; fi
青年人

  

#!/bin/bash

if [ $1 -lt 18 ]
then
        echo "未成年"
else
        echo "成年了"
fi
[root@hadoop100 scripts]# ./if_test.sh 20
成年了

  

#!/bin/bash

if [ $1 = 1 ]
then
    echo 输入了个1
elif [ $1 = 2 ]
then
    echo 输入了个2
else
    echo 输入的是其他
fi
[root@hadoop100 scripts]# ./if_elif_else_test.sh 2
输入了个2

  

#!/bin/bash

# 输入参数表示年龄,判断属于哪个年龄段
if [ $1 -lt 18 ]
then
    echo 未成年人
elif [ $1 -lt 35 ]
then 
    echo 青年人
elif [ $1 -lt 60 ]
then 
    echo 中年人
else
    echo 老年人
fi
[root@hadoop100 scripts]# ./if_elif_else_test2.sh 20
青年人

  

  

  

case 语句

  

(1) 基本语法:

case $变量名 in
值1)
    执行程序1
;;
值2)
    执行程序2
;;
    ......
*)
    如果变量的值都不是以上的值,则执行此程序
;;
esac

  

注意事项:

  1. case行尾必须为单词 in ,每一个模式匹配必须以右括号 ) 结束。
  2. 双分号 ;; 表示命令序列结束,相当于Java中的break。
  3. 最后的 *) 表示默认模式,相当于Java中的 default 。

  

(2) 练习:

#!/bin/bash

case $1 in
1)
    echo one
;;
2)
    echo two
;;
3)    
    echo three
;;
*)
    echo number else
;;
esac
[root@hadoop100 scripts]# ./case_test.sh 2
two
[root@hadoop100 scripts]# ./case_test.sh 8
number else

  

  

  

for 循环

  

(1) 基本语法:

for (( 初始值;循环控制条件;变量变化))
do
    程序
done

  

(2) 练习:

#!/bin/bash

for (( i=1;i<=$1;i++ ))
do
    sum=$[ sum+i ]
done
echo $sum
[root@hadoop100 scripts]# ./for_test.sh 100
5050

  

(3) 基本语法2:

for 变量 in 值1 值2 值3...
do
    程序
done

增强for循环

  

(4) 练习2:

[root@hadoop100 scripts]# for i in 哈哈 嘿嘿 呵呵; do echo $i; done
哈哈
嘿嘿
呵呵

[root@hadoop100 scripts]# for i in {1..100}; do sum=$[sum+i]; done; echo $sum
5050

小tips:

  • ;就代表换了一行
  • {1..100} 表示生成序列,1到100的序列,用于增强for遍历

  

  

  

while 循环

  

(1) 基本语法:

while [ 条件判断式 ]
do
    程序
done

  

(2) 练习:

#!/bin/bash

a=1
while [ $a -le $1 ]
do
#    sum=$[ sum+a ]        第一种写法
#    a=$[ a+1 ]
    let sum+=a        # 第二种写法
    let a++
done
echo $sum
[root@hadoop100 scripts]# ./while_test.sh 100
5050

  
  
  

  

read 读取控制台输入

  

  

(1) 基本语法:

read (选项) (参数)


① 选项:

  -p:后跟输入时的提示句。

  -t :后跟输入时系统等待的时间(秒),如果不加 -t 则系统会一直等待。

② 参数:

  变量:指定某个变量,随后运行时把值输入给它。

  
  

(2) 练习:

#!/bin/bash

read -t 10 -p "请输入名字:" name
echo Welcome,$name

如果一直不输入,10秒后,程序会自动结束

[root@hadoop100 scripts]# ./read_test.sh
请输入名字:Welcome,

  
如果及时输入了,则程序会正常执行

[root@hadoop100 scripts]# ./read_test.sh
请输入名字:tony
Welcome,tony

  
  
  

  

函数

  

  

  

一、系统函数

  

  

1、basename

  

(1) 基本语法:

basename [string/pathname] [suffix]

功能描述:basename 命令会删掉所有的前缀包括最后一个 / 字符,即只保留最后一个 / 之后的字符。

basename 可以理解为取路径里的文件名称。

  

选项:

  suffix :指定要去掉的后缀。如果 suffix 被指定了,basename 会被 pathname 或 string 中的 suffix后缀 去掉。

  
  

(2) 练习:
  

截取路径:

[root@hadoop100 scripts]# basename /root/scripts
scripts


还能截取普通字符串:

[root@hadoop100 scripts]# basename hdasgfua/adgdkh/dfajgk/hahaha
hahaha


加上 suffix 参数去掉指定后缀:

[root@hadoop100 scripts]# basename /root/scripts/hello.sh .sh
hello

去掉了 .sh 后缀

如果 suffix 不是后缀,则错了,不会执行此参数:

[root@hadoop100 scripts]# basename /root/scripts/hello.sh hello
hello.sh

不能去掉 hello 留 .sh ,因为 hello 不是后缀。

  

  

2、dirname

  

(1) 基本语法:

direname string/pathname

功能描述:对于pathname,从给定的包含绝对路径的文件名中去除文件名(非目录部分),然后返回剩下的路径(目录部分);对于字符串,删掉后缀包括最后一个 / 字符,即只保留最后一个 / 之前的字符。

dirname 可以理解为取文件路径的绝对路径名称。

  
  

(2) 练习:
  
截取路径:

[root@hadoop100 scripts]# dirname /root/scripts/hello.sh
/root/scripts


还能截取普通字符串:

[root@hadoop100 scripts]# dirname /hello/java/hadoop/world
/hello/java/hadoop

  

  

  

二、自定义函数

  

  

(1) 基本语法:

function 函数名()
{
    程序;
    return int;
}


简化版:

函数名()
{
    程序;
}

function、return 返回值都可以选写。

  

(2) 经验技巧:

  1. 必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其他语言一样先编译。
  2. 函数返回值,只能通过 $? 系统变量获得,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return 后跟数值 n(0-255)

  

(3) 练习:

#!/bin/bash

function add(){
    s=$[$1+$2]
    echo "两数之和为:"$s
}

read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b

add $a $b
[root@hadoop100 scripts]# ./fun_test.sh
请输入第一个整数:35
请输入第二个整数:25
两数之和为:60

  

改进版:
函数中最后用 echo 模拟返回函数的返回值。

#!/bin/bash

function add(){
        s=$[$1+$2]
        echo $s
}

read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b

sum=$(add $a $b)
echo "两数之和为:"$sum

  
  
  

  

文本处理工具

  

  

  

cut

  

cut 的工作就是 “剪”,具体地说就是在文件中负责剪切数据用的。cut 命令从文件的每一行剪切字节、字符和字段,并将这些字节、字符和字段输出。

  
(1) 基本用法:

cut [选项参数] filename

说明:默认分隔符是制表符 \t

  

(2) 选项参数说明:

  -f :列号。提取第几列

  -d :分隔符。按照指定分隔符分割列,默认是制表符 \t

  -c :按字符进行切割,后加数字,表示取第几列。比如 -c 2

  

(3) 练习:

查看要用的数据

[root@hadoop100 scripts]# cat cut.txt
dong shen he
guan zhen nan
wo wo wo
lai lai lai
le le le

  
切割 cut.txt 第一列

[root@hadoop100 scripts]# cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le

  
切割 cut.txt 第二、三列

[root@hadoop100 scripts]# cut -d " " -f 2,3 cut.txt
shen he
zhen nan
 wo
 lai
 le

  
在 cut.txt 文件中切割出 guan

这能截取一行

[root@hadoop100 scripts]# cat cut.txt | grep guan
guan zhen nan

这一行中再切第一列

[root@hadoop100 scripts]# cat cut.txt | grep guan | cut -d " " -f 1
guan

  

  

awk

  

一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

  
(1) 基本用法:

awk [选项参数]  '/pattern1/{action1}  /pattern2/{action2}...'    filename

  

pattern:表示 awk 在数据中查找的内容,就是匹配模式

action :在找到匹配内容时所执行的一系列命令

  

(2) 选项参数说明:

  -F :指定输入文件的分隔符

  -v :赋值一个用户定义变量

  

(3) 练习:

搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第7列

[root@hadoop100 scripts]# cat /etc/passwd | grep ^root | cut -d ":" -f 7
/bin/bash
[root@hadoop100 scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $7}'
/bin/bash

  
搜索 passwd 文件以 root 关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”分割。

[root@hadoop100 scripts]# cat /etc/passwd | awk -F ":" '/^root/ {print $1","$7}'
root,/bin/bash
相关文章
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
1月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
2月前
|
Shell
Shell编程(下)
Shell编程(下)
113 1
|
2月前
|
Shell Linux Windows
Shell编程(上)
Shell编程(上)
52 1
|
2月前
|
Shell Linux 开发工具
|
2月前
|
监控 Unix Shell
shell脚本编程学习
【10月更文挑战第1天】shell脚本编程
84 12
|
3月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
3月前
|
存储 Unix Shell
shell脚本编程基础
【9月更文挑战第4天】
56 12
|
3月前
|
Shell Linux
Shell 编程 编写hello word
Shell 编写hello word
59 5