shell 学习笔记

Posted 皮卡丘吉尔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell 学习笔记相关的知识,希望对你有一定的参考价值。

shell学习笔记

一. 基本语法

1.1 基本操作

  1. 包含头文件 用来做解析。
#! /bin/bash 

上面是用 /bin/bash 来解析脚本 也可以用 /bin/sh 来解析的

  1. 输出信息

比如我们C的printf 在shell 可以用 echo 来输出。
下面是输出 hello world 这个字符串

#! /bin/bash
echo "hello world" #输出 hello world 字符串

也可以直接在你的终端执行 echo "hello world" 一样的效果 如下图

  1. 如何运行脚本
    比如你的脚本名字叫 1-hello.sh (一般会 用.sh 作为后缀,不用也可以。)
    执行这个有好多种方法,我这里就写几种我想到的。
# 第一种 最常用
./xx.sh #这种你需要 给它一个可执行权限 
#命令: chmod +x xx.sh 才可以执行.

# 第二种
bash xx.sh

# 第三种
sh xx.sh

也可以看下方我在终端执行的命令

  1. echo 的简单使用
    echo 不单单就是输出信息 其实它是一个命令,其实用的别的也很多。

指令:

首先我这里建立一个文件 叫 xx 里面内容为空

touch xx

然后我通过echo 方式 写 hello world 到 xx文件中。(不先创建 xx也是可以的,如果你没有xx文件,下面指令也会给你创建的)

echo "hello world" > xx

> 是会将内容覆盖的 就是会原来有数据 将会被清空, 再写入内容
如图所示:

如果不想覆盖原来的 在后面增加进去,则可以用下方的这个
指令:
把 hello world 追加到 xx 文件

echo "hello world" >> xx

>> 是追加的方式写入文件 原有的内容保留,再末尾添加内容

1.2 变量

首先得知道下面的几种符号的含义。

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

$#
	获取所有输入参数的个数 常用于循环 判断参数的个数是否正确以及加强脚本的健壮性。

$*
	这个变量代表命令行中的所有参数 $*把所有的参数看成一个整体

$@ 
	这个变量也代表命令行中的所有参数 不过$@把每一个参数区分对待

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

变量的定义 (变量没有类型的,所以直接写就行了)
简单的代码实例

#! /bin/bash
num=10
string="hello world"

echo $num		#输出 num 的值
echo $string	#输出 string 的值

运行结果:

环境变量
下面的操作只能在同一个终端才有效。

  1. 在终端:创建环境变量 一个 XX 为 100 的这么个环境变量
export XX=100
  1. 在终端查看有哪些环境变量
export
  1. 在终端删除环境变量 XX
unset XX
  1. 输出环境变量XX的内容
echo $XX
  1. 用户级变量操作
    环境变量得写到 ~/.profile 文件中去.
    比如把这个XX=100添加到 ~/.profile 文件中去
echo "export AA=100" >> ~/.profile 

执行这个指令 让上面这行 生效

source ~/.profile   

输出环境变量值

echo $XX   
  1. 系统级变量
    系统级变量 那么我们得写到 /etc/profile 里面去

把这个 export AA=100 输出到 /etc/profile 里面去

echo "export AA=100" >> /etc/profile    	

执行这个文件 让我们指令生效

source /etc/profile

输出环境变量值

echo $AA   

1.3 数组

#! /bin/bash
################################# 常用数组 #################################
array1=(1 2 3 4 5)
array2=('1' '2' '3' '4' '5')
array3=("111" "222" "333" "444" "555")

echo $array1[0] #输出第0个元素
echo $array2[1] #输出第0个元素
echo $array3[2] #输出第0个元素

echo $array3[@]  #输出所有元素
echo $#array3[@] #输出元素个数
echo $!array3[@] #输出所有下标

echo $array3[@]:1     #输出从下标为1开始输出
echo $array3[@]:1:2   #输出从下标为1开始输出  到 下标为2结束


################################# 关联数组 #################################
#定义方式
declare -A array4
declare -A array5

#单个赋值
array4[num]=4
array4[name]="pipi"
array4[score]=60

#全部赋值
array5=([num]=5 [name]="keke" [score]=50)

#输出信息
echo $array4[@]
echo $array5[@]

1.4 命令行获取参数

这个就相当于我们 main函数的参数 int main(int argc,char **argv) 运行的时候 就带上参数。

这里先说一下 $n
n:为数字 $0代表该脚本的名称 $1~$9代表第一到第九个参数十以上的参数需要用大括号包含如 $10

我们还是直接写个小示例

#! /bin/bash

name=$1

echo "hello $name"
echo "参数个数为 $#"
echo "所有参数为 $*"

执行结果:

1.5 数学运算 多种方法

数学运算 方式1

#! /bin/bash 
# 方式1
# 注意: 用下方let 方式计算 不能有空格不能如 num=num + 100 这是错误写法

num=100

# 加法
let num=num+100

# 减法
let num=num-100

# 乘法
let num=num*100

# 除法
let num=num/100

echo $num

数学运算 方式2

#! /bin/bash 
# 方式2
# 注意: 下方写法表达式内可以用空格隔开 如 num=$[ num + 100 ] 这是可以的

num=100

# 加法
num=$[num+100] 或 num=$[ num + 100 ]

# 减法
num=$[num-100] 或 num=$[ num - 100 ]

# 乘法
num=$[num*100] 或 num=$[ num * 100 ]

# 除法
num=$[num/100] 或 num=$[ num / 100 ]

echo $num

数学运算 方式3

#! /bin/bash 
# 方式3
# 注意: 下方写法表达式内可以用空格隔开 如 num=$(( num + 100 )) 这是可以的

num=100

# 加法
num=$((num+100)) 或 num=$(( num + 100 ))

# 减法
num=$((num-100)) 或 num=$(( num - 100 ))

# 乘法
num=$((num*100)) 或 num=$(( num * 100 ))

# 除法
num=$((num/100)) 或 num=$(( num / 100 ))

echo $num

数学运算 方式4

#! /bin/bash 
# 方式4
# 注意: 下方表达式必须 空格 隔开 !!! 

num=100

# 加法
num=`expr $num + 100`   

# 减法
num=`expr $num - 100` 

# 乘法
num=`expr $num \\* 100`  # *符号前面请加 \\

# 除法
num=`expr $num / 100`

echo $num

以上就是不同方式进行 数学运算的方法了,我个人还是觉得用 方式3 好点。

1.6 if 语句

示例代码:

1.61 if 整数比较

整数比较 方式1

用表中符号来判断 想了解判断符号可在终端输入命令 man 1 test 来查看.

符号等价于C语言的符号
-eq==
-ne!=
-gt>
-lt<
-ge>=
-le<=

示例:

#!/bin/bash

num=$1  #获取一个命令行参数
######################## 方式1 ########################
if [ $num -eq 100 ]
then
    echo "等于100"
elif [ $num -gt 100 ]
then
    echo "大于100"
else
    echo "小于100"
fi

# 或者也可以加上双引号 如下

if [ "$num" -eq "100" ]
then
    echo "等于100"
elif [ "$num" -gt "100" ]
then
    echo "大于100"
else
    echo "小于100"
fi

也可以不用上面表中符号,直接用 >>=、 等符号 但是请用 (()) 来写。
示例

整数比较 方式2

#!/bin/bash
######################## 方式2 ########################
if (( $num == 100 ))
then
    echo "等于100"
elif (( $num >= 100 ))
then
    echo "大于100"
else
    echo "小于100"
fi

# 或者也可以加上双引号 如下

if (( "$num" == "100" ))
then
    echo "等于100"
elif (( "$num" >= "100" ))
then
    echo "大于100"
else
    echo "小于100"
fi

1.62 if 字符串比较

字符串比较 方式1

[]的表示方式 其中用 === 都是可以的

#! /bin/bash
string1="hello"
string2="hello"

if [ $string1 = $string2 ]
then
    echo "字符串一样"
else
    echo "字符串不一样"
fi

# 也可以加上双引号 如下方

#! /bin/bash
string1="hello"
string2="hello"

if [ "$string1" = "$string2" ]
then
    echo "字符串一样"
else
    echo "字符串不一样"
fi

字符串比较 方式2

[[]] 的表示方式 其中用 === 都是可以的

#! /bin/bash

string1="hello"
string2="hello"

if [[ $string1 == $string2 ]]
then
    echo "字符串一样"
else
    echo "字符串不一样"
fi

# 也可以加上双引号 如下方

#! /bin/bash
string1="hello"
string2="hello"

if [[ "$string1" == "$string2" ]]
then
    echo "字符串一样"
else
    echo "字符串不一样"
fi

1.7 switch语句

示例代码:
)相当于C语言的case中的:;;相当于C语言的 break;

#! /bin/bash

# 获取键盘上值 (相当于C语言的 scanf)
read num

case $num in
	[a-z])
	    echo "小写字母"
	    ;;
	[A-Z])
	    echo "大写字母"
	    ;;
	[0-9])
	    echo "数字"
	    ;;
	*)
	    echo "其它"
	    ;;
esac

1.8 for 语句

for 方式1

示例代码:

#! /bin/bash

# 循环3次 分别 i 的值是 0、1、2
for ((i=0;i<3;i++))
do
        touch $i
        echo "hello $i" > $i
done

# 也可以用空格隔开如下
for (( i=0; i<3; i++ ))
do
        echo $i
done

# 也可以用空格隔开如下
for (( i = 0; i < 3; i++ ))
do
        echo $i
done

# 一般比较多的是我们去 遍历数组里面的元素 把每一个元素打印出来
#! /bin/bash
# 数组的定义 
array=( "111" "222" "333" )

# 遍历每一个元素,并输出
for (( i = 0; i < $#array3[@]; i++ ))
do
	echo "$i"
done

# $#array3[@] 就是指数组元素个数

# 输出结果:
111
222
333

for 方式2

#! /bin/bash

# 循环3次 分别 i 的值是 0、1、2
for i in 0..2
do
    echo $i
done


# 在shell中是没有类型这说法的,所以for循环字符串也是可以的。 
# 数组的定义
array=( "111" "222" "333" )

# 遍历每一个元素,并输出
for i in $array[@]
do
    echo $i
done

# $array[@]  是指所有元素

# 输出结果:
111
222
333

for 方式3

# 循环3次 分别 i 的值是 0、1、2
for i in 1 2 3
do
    echo $i
done

# 可以随意写 字符串也可以的
# 循环3次 分别 i 的值是 0、100、1000
for i in 1 100 1000
do
    echo $i
done

# 也可以这样
# 循环3次 分别 i 的值是 111、222、333
for i in "111" "222" "333"
do
    echo $i
done

1.9 while 语句

#!/bin/bash

# 死循环
while :
do
    # 在这里添加要执行的代码
done


# 不断获取键盘值 并且输出 read 就相当于 C语言的 scanf()
while read i
do
    echo $i
done

# 不断从xx.txt文件中读取内容 并且输出
while read i
do
    echo $i
done < xx.txt

二. 正则表达式

正则表达式
通常被用来检索/替换那些符合某个模式的文本,在linux中
grep, sed, awk 等文本处理工具都支持通过正则表达式进行模式匹配。下面表中符号切记记住,因为经常会用来结合 三剑客的。

符号描述
^匹配行首,比如 ^hello 就是匹配以 hello 开头的行
$匹配结尾,比如 hello$ 就是匹配以 hello 结尾的行
.匹配任意一个字符(除了换行符)
*前一个字符匹配0次或任意多次
[]匹配中括号里面指定的任意一个字符,只匹配一个字符, 例如 [abc] 表示匹配a、b、c 这三个任意一个字符。[a-z] 表示匹配是小写字母,[0-9] 表示匹配是数字0~9。
[^]匹配除了中括号的字符之外的任意一个字符,跟上述是相反的。例如 [^abc] 匹配的是除了a,b,c的其他任意字符。[^0-9] 表示匹配除了数字的任意字符。

1. grep

基本用法

grep 是一个文件过滤工具。
grep [options] [pattern] file

选项参数说明

作用:文本搜索工具,过滤 条件

选项参数描述
-iignorecase 忽略字符大小写
-o仅显示匹配到的字符串本身
-v显示不能被模式匹配的行
-E支持用扩展的正则表达式
-q静默模式,即不输出任何信息
-n显示行号
-c只统计匹配行数
-w只匹配过滤的单词
–color=auto使用grep过滤结果添加颜色

演示示例

常规匹配
一串不包含特殊字符的正则表达式 匹配它自己,例如

  1. 比如查看 aa.c 文件 中 找 字符串 abc
cat aa.c | grep adc
  1. 查看 aa.c 文件中 以 abc 开头的字符串
cat aa.c | grep ^abc
  1. 查看 aa.c 文件中 以 abc 结尾的字符串
cat aa.c | grep abc$
  1. 查看 aa.c 文件中 以 abc 开头 并且 以 abc 结尾 的字符串
cat aa.c | grep ^abcabc$		(这样写法只有 abcabc 才能匹配上)
  1. 查看 aa.c 文件中 空行
cat aa.c | grep ^$
  1. 如果要显示行号 请加上 -n
cat aa.c | grep -n ^$
  1. 查看 aa.c 文件中 以 i 开头, 中间两个任意字符(包括特殊符号), f 结尾的 字符串
cat aa.c | grep i..f
  1. 特殊字符 匹配一个任意的字符 (包括特殊字符等)
.
  1. *
    不单独使用,他和上一个字符连用,表示匹配上一个字符0次或多次,例如 下面会匹配 rot root rooot roooot…等
cat aa.c | grep ro*t
  1. 匹配任意一个字符 出现任意次
cat aa.c | grep .*
  1. 查看 aa.c 文件中 以 i 开头 以 f 结尾
cat aa.c | grep ^i.*f$
  1. 查看 aa.c 文件中 以 i 开头 中间随意 然后 出现 in 然后中间随意 f 结尾的字符串
cat aa.c | grep ^i.*in.*f$


字符区间[]

  • [] 表示匹配某个范围内的一个字符,例如
  • [6,8] 匹配6或者8
  • [0-9] 匹配一个0~9的数字
  • [0-9]* 匹配任意长度的数字字符串
  • [a-z] 匹配一个a-z之间的字符串
  • [a-z]* 匹配任意长度的字母字符串
  • [a-c,e-f] 匹配a-c 或者 e-f 的任意字符
  1. 查看 aa.c 文件中 出现 i开始 中间是字符a-z 不限个数 f
cat aa.c | grep i[a-z]*f
  1. 查看 aa.c 文件中 出现 $字符的字符串 需要转义
cat aa.c | grep '\\$'

grep 也可以配合 选项参数 来进一步获取想要的内容。我这里就不写那么多了。

2. awk

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

基本用法

  • awk [option] 'pattern[action]' file...
  • pattern:
    • 表示awk 在数据中查找的内容 就是匹配模式。
  • action:
    • 在找到匹配内容时所执行的一系列命令。
  • file
    • 对应的文件名

awk 可选参数 模式 '条件动作' 文件

选项参数说明

默认是空格作为空格符,且多个空格也识别成为一个空格 作为分隔符
awk是按行处理文件 一行处理完毕 处理下一行 …
自定义输出,必须外层单引号,内层双引号。

  • -F 指定分隔符
  • -v 定义或修改一个awk内部的变量
  • -f 从脚本文件中读取awk命令

下面是 awk 特殊的内置变量, 这里只是列举了我常用的,更多命令 可通过 命令 man awk 查看

选项参数描述
$0所有内容
$n第n列。例如 $1 就是第 1 列,$10 就是第 10 列
$NF最后一列
$(NF-n)倒数第n列。例如 倒数第二列则是 $(NF-1)
NR行数。 例如 NR==1 就是第一行
FILENAME文件名

演示示例

如果不懂第几列 行的概念,我这里就举例一下。
比如我有一个文件叫 xx ,内容如下

AAA BBB CCC DDD EEE
111 222 333 444 555
!!! === --- *** +++
  1  22 333 444 555


是不是很容易理解,awk 是 按空格 来分割的,按行处理的。

再来一个 示例 free -m 列出内容如下图,记得是按 空格 分割的。下面同颜色框起来的为同一列

下面就开始列举一些示例

  1. 获取 xx 文件中全部内容$0 表示所有内容
awk 'print $0' xx
  1. 获取 xx 文件中第一列内容, $1 表示第一列 (第列 就 $n)
awk 'print $1' xx
  1. 获取 xx 文件中 最后一列内容, $NF 表示最后一列
awk 'print $NF' xx
  1. 获取 xx 文件中 第一列和第二列内容 并且空格隔开。
awk 'print $1,$2' xx
  1. 获取 xx 文件中第一行所有内容, NR==1 表示第一行,$0 表示 所有内容。(第n行 就 NR==n)
awk 'NR==1 print $0' xx
  1. 获取 xx 文件中第一行,第二行所有内容
awk 'NR==1,NR==2 print $0' xx
或
awk 'NR==1 || NR==2 print $0' xx
  1. 获取 xx 文件中 第一行到第三行的所有内容
awk '(NR>=1)&&(NR<=3)print' xx
  1. 获取 xx 文件中 奇数 行 所有内容
awk '(NR%2)==1 print $0'  xx
  1. 获取 xx 文件中 偶数 行 所有内容
awk '(NR%2)==0 print $0'  xx
  1. 获取 xx 文件中 第一行 第一列 内容
awk 'NR==1 print $1' xx

指定符号分割操作

  1. 获取 xx 文件中 按 : 符号 进行分割,第一列内容。 指定符号分割 加上 -F "符号" 即可
awk -F ":" 'print $1' xx

这个还是比较简单,这里就不多演示了。

寻找文件中是否 有需要找的 字符串

  1. 输出 xx 文件中 AAA字符串的 行内容
awk '/AAA/ print $0' xx
  1. xx 文件中 第二行 第一列中的 111 +1 变成 112. (注意: +1操作不会影响文件中本身的值,还是保持 111)

方式1 直接 +1

awk 'NR==2 print $1+1' xx

方式2 可以通过-v 引入变量 实现运算

awk -v i=1 'NR==2 print $1+i' xx
  1. 获取 xx 文件中所有内容,并且在每一行后面加上 " XXX" (这里只是输出,并不是会在原文件添加 " XXX")
awk 'print $0 " XXX"' xx
  1. 如果想在 输出信息前和输出信息后增加打印信息 可以看下方示例
    获取 xx 文件中 第一行 内容,并且在输出第一行内容前 输出 "hello" 在输出第一行内容后 输出 "world"
  • BEGIN: 在所有数据读取行之前执行
  • END: 在所有数据执行后执行
awk 'BEGINprint "hello" NR==1print $0 ENDprint "world"' xx

输出结果如下:

hello
AAA BBB CCC DDD EEE
world
  1. 输出xx 文件中当前文件名 并且输出第一行的内容,并且空格隔开。
awk 'NR==1 print FILENAME,$1' xx
  1. 小示例: 用awk 获取 IP 地址
ifconfig | awk '/netmask/ print $2'

结果如下:

192.168.1.101
127.0.0.1

3. sed

基本语法

sed 用法
sed [项目] [sed内置命令字符] [输入文件]

选项参数

下面表的内容只是一部分。

选项参数描述
-n取消默认sed的输出 常与sed内置命令p一起用
-i直接将修改结果写入文件 不用-i sed修改的是内存数据
-e多次编辑 不需要管道符了
-r支持正则扩展

下面是 sed 的 内置命令

内置命令描述
aappend 对文本追加 在指定后面添加一行/多行文本
dDelete 删除匹配行
iinsert 表示插入文本,在指定行前添加一行/多行文本
pprint 打印匹配行的内容 通过p与-n 一起用
c替换指定的整行内容

演示示例

下面写一些操作示例。

获取文件内容

  1. 获取 xx 文件中 第一行内容 (请加上 -n 不然是所有内容都输出的. 想输出第n行就改成 'np' )
sed -n '1p' xx
  1. 获取 xx 文件中 所有内容
sed -n 'p' xx
  1. 获取 xx 文件中 第一行到第三行 内容
sed -n '1,3p' xx
  1. 获取 xx 文件中 最后一行 内容
sed -n '$p' xx

给文件添加内容

如果想要将修改结果写入文件 请一定要在sed 后面 加上 -i
如果想要将修改结果写入文件 请一定要在sed 后面 加上 -i
如果想要将修改结果写入文件 请一定要在sed 后面 加上 -i
不加 -i 是不会真正修改的,只是输出给你看而已。(调试建议还是先不加,免得乱改文件内容)

我下面是没有加 -i 的,所以下面的命令不会对文件进行修改。

在指定行上面添加内容

  1. xx 文件 第一行的上面插入 “hello world” (ni+要插入的内容,其中n代表行号)
sed '1ihello world' xx
  1. xx 文件 最后的行上面插入 “hello world” 到文件末尾 ($i+要插入内容)
sed '$ihello world' xx
  1. xx 文件 每一行的上面插入 “hello world” (i+要插入的内容)
sed 'ihello world' xx

在指定行下面添加内容

  1. xx 文件 第一行的下面插入 “hello world” (na+要插入的内容,其中n代表行号)
sed '1ahello world' xx
  1. xx 文件 最后的行下面插入 “hello world” 到文件末尾 ($a+要插入内容)
sed '$ahello world' xx
  1. xx 文件 每一行的下面插入 “hello world” (a+要插入的内容)
sed 'ahello world' xx

指定字符行添加内容

  1. xx 文件 凡是以 “AAA” 开头的,在该行的上面插入 “hello world”
sed '/^AAA/ihello world' xx
  1. xx 文件 凡是以 “AAA” 开头的,在该行的下面插入 “hello world”
sed '/^AAA/ahello world' xx

替换指定的整行内容

  1. xx 文件中 把第一行内容 换成 “hello world” (第1行就 1c ,第n行 则是 nc)
sed '1chello world' xx
  1. xx 文件中 把所有行内容 换成 “hello world”
sed 'chello world' xx
  1. xx 文件中 把 “AAA” 开头的行 都换成 “hello world”
sed '/^AAA/chello world' xx

替换指定的字符
语法格式:
sed "s/需要替换的内容/新的内容/g" 文件名

s :替换指定字符
g :全局的意思

  1. xx 文件中 AAA 改成 666. 不加 g 则替换一个, 加上 g 则是全局替换
sed 's/AAA/666/g' xx

删除指定的整行内容

  1. xx 文件中 删除第一行内容 (想删除第一行就 1dn行就 nd)
sed '1d' xx
  1. xx 文件中 删除最后一行内容
sed '$d' xx
  1. xx 文件中 删除第一行到第三行内容
sed '1,3d' xx

4. cut

基本语法

文本处理工具

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

cut [选项参数] filename
说明 默认分割符是制表符

选项参数

选项参数描述
-f列号 提取第几列
-d分割符 按照指定分割符分割列 默认是制表符 “\\t”
-c按字符进行切割 后加加n 表示取第几列 比如 -c 1

演示示例

还是用这个 xx 文件内容来举例把
xx 文件内容如下

AAA BBB CCC DDD EEE
111 222 333 444 555
!!! === --- *** +++
  1  22 333 444 555
  1. 获取 xx 文件中 以一个空格 进行裁剪 输出第一列内容 (-d 指定分割符号 -f 指定获取第几列)
cut -d " " -f 1 xx

输出内容如下:

AAA
111
!!!

结果看出来了吧,cut 和 awk 是不一样的

  1. 获取 xx 文件中 第一列到第三列 内容 以一个空格进行裁剪
cut -d " " -以上是关于shell 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

基于Java的大整数运算的实现(加法,减法,乘法)学习笔记

shell 里面的计算

项目零贰号 | 蜂蜜笔记:打通玩乐与学习,在信息爆炸的时代帮你轻松做减法#SANDBOX#

shell笔记:移动文件

shell 处理小数位加减法(比较)运算

Linux学习笔记-Shell教程