Shell命令行知识点总结

Dracary 发布于 2026-03-11 345 次阅读


sed

我们先来学习sed

我们知道sed -n "1p" file可以在终端输出文件的第一行,而sed -n "1,3p" file可以在终端输出文件的第一至三行,而sed -n "1p;3p" file则是在终端输出文件的第一行和第三行

有一个高阶的技巧是sed -n "1,$ p" file可以输出文件的第一行至最后一行的所有内容,至于为什么要加空格,是因为shell在双引号时会自动解析符号$,而$p在此处没有意义,不过你也可以使用sed -n "1,\$p" file,既然说到这里了,顺便补充一点,假如你想命名一个文件,它依赖于变量a的值,但是a在中间,你可以touch "file${a}next"

当然你也可以使用单引号,shell就不会自动解析$了,也就是sed -n '1,$p' file,此外如果你只想打印第一行和最后一行,你可以使用sed -n '1p;$p' file

还有的高阶技巧比如sed -n "1~2p" file表示从第一行开始每隔着两行打印一次

所以假如题目要求写一个脚本,对于给定的数字参数n,输出给定文件的第n至最后一行的所有内容,代码可以是

sed -n "$1,$ p" file
# or sed -n "$1~1p" file

这里补充一下对于脚本命令行./command a1 a2 a3 a4 ... an,其中$1 $2 $#分别代表a1 a2以及参数个数

向指定文件插入特定行,在第1行前插入,命令行为sed "1i\I want you!" file

在第1行后插入,命令行为sed "1a\I love you!" file

替换第一行的内容,命令行为sed "1c I love you" file

对于字符串替换,如果需要替换完整单词,可以是sed "s/\<word\>/replace/g" file

如果你不需要区分大小写且想要全局替换,命令行可以是sed "s/you/me/gi" file

补充对于字符串替换的知识点,对于sed -n "s/you/me/g" file,它是不会输出任何内容的,因为sed默认输出文件的所有内容,-n代表关闭这种默认输出,所以不会有任何内容,如果你需要打印替换的行的内容,你可以使用sed -n "s/you/me/gp" file,注意这里如果不加-n,被替换的特定行会被打印两次

sed与正则化

正则里.代表任意字符,*代表前一个字符重复0次或多次,+代表前一个字符重复1次或多次,?代表前一个字符重复0次或1次,而^$分别代表行首和行尾,[0-9]代表数字,[a-z]代表小写字母,[A-Z]代表大写字母,[a-zA-Z]代表所有大小写字母

seq

接着我们学习seq考虑需求:往指定文件中写入0-20的所有整数

通常我们会这样写

#!/bin/bash
a=0
for((a=0;a<=20;a++))
do
    echo "$a" >> file
done

实际上可以一行完成

seq 0 20 > file

echo与单双引号

以下命令行都是基于bash

考虑命令行echo "printf("value REPLACE\n");"

你会得到

printf(value REPLACEn);

如果是echo "printf(\"value REPLACE\\n\");"或者echo "printf(\"value REPLACE\n\");"

你会得到

printf("value REPLACE\n");

如果是echo 'printf("value REPLACE\n");'

你才能得到

printf("value REPLACE\n");

反过来如果是双引号内部嵌入单引号echo "printf('value REPLACE\n');",可以得到

printf('value REPLACE\n');

还需要强调的就是双引号内部不能套双引号,单引号内部不能套单引号,需要加转义字符

但是单引号转义自己会报错echo 'printf(\'value REPLACE\n\');'

但是二者内部却可以互相套彼此

basename

假设给定

filename=src/main/main.c

我们使用basename $filename可以得到main.c

进一步的我们可以

name=$(basename $filename| cut -d. -f1)

这里$(command)相当于执行shell命令并且返回结果

更高级一点,我们使用basename 文件名 后缀比如basename ./code/aaa.sy .sy可以得到aaa

与之相反,如果我们使用dirname ./code/aaa.sy可以得到./code

find

基本命令行为find FileDir -name FileName,比如

find . -name "test.sh"

()与[]及其衍生

(())支持算术运算下的条件判断,可以用于数值的比较,使用的是==而不是=,前者是比较是否相等,后者则是赋值,比如

#!/bin/bash

a=1
if ((a==1))
then
    echo "1"
fi

b=0
for ((b=0;b<=20;b++))
do
    echo "yeyeye"
done

if ((a==b))
then
    echo "yes"
elif ((a!=b))
then
    echo "no"
fi

$(())支持算术运算且会返回结果,比如

a=1
b=$((a+1))

此外,补充一个常用知识点

n=$((${1:-2}+${2:-1}))

表示$1存在就使用该值,否则使用默认的2;如果$2存在就使用该值,否则使用默认的1,记住:后面有-

此外[[]]基本就是[]的平替,而且支持的内容更多,其中字符串比较使用===都可以,不能使用-eq,数值比较时推荐使用-eq,虽然也可以使用===,但本质上是字符串比较,对于01010数值上相等(可能还会由于shell的版本问题导致判不等)但是字符串意义上不相等

a="hello"
b="hello"

if [[ $a == $b ]]
then
    echo "111"
fi

if [[ $a == "$b" ]]
then
    echo "222"
fi

grep

使用grep "you" file默认不显示行号,可以使用-n来显示;如果还想要不区分大小写,使用-i

合起来就是

grep -ni "you" file

递归搜索文件夹,使用grep -r "you" FileDir

如果需要搜索多个字符串可以使用下列方法,并且无先后顺序之分:

grep -E "you|me" file
#or grep -e "you" -e "me" file
#or grep "you\|me" file

awk

基本结构为

awk '条件 { 动作 }' 文件

如果只有动作,我们使用awk '{print $1}' file来打印文件的第一列,这里一般使用单引号,如果使用双引号可能会被提前解析,此外$0代表整行,默认分隔符是空格和制表符,我们使用-F来控制分隔符

如果只有结构,我们使用awk '/bash/' file来打印包含bash的行,等价于grep "bash" file,注意两边的/不能去掉

如果二者都有,比如awk '/bash/ {print $1}' file代表打印出现bash的行的第一列

一个高级的做法你可以使用awk "/$CMD/"' {print $1}'file既使用双引号解析传入的变量,又保留单引号解析awk自身的变量$1,此外补充一点就是系统会自动拼接相邻的字符串,"abc"'def'"ghi"会被解析为abcdefghi

此外,NFawk中可以表示列的个数,如给定:

A 25 27 50
B 35 75
C 75 78 
D 99 88 76

我们可以这样筛选B和C:

awk 'NF<4 {print "Not all scores are available for "$1}'

还可以对数值进行判断,给定数据:

A 25 27 50
B 35 37 75
C 75 78 80
D 99 88 76

我们可以这样筛选不及格:

awk '{if($2<50||$3<50||$4<50) print $1" : Fail";else print $1" : Pass"}'

可以注意到if语句也是在大括号内部的,大括号外面的是用来筛选行的

一个比较综合的问题,如果给定数据格式为

USER PID PPID PRI CMD

同时我们给出$PID,要求你通过它找到$PPID直到0停止

代码如下:

pp=$PID
while [[ $pp -ne 0 ]]
do
    pp=$( awk -v p=$pp '$2==p {print $3}' $FILE )
    echo $pp
done

其中-v表示传入终端变量加入awk

这里是紫罗兰的永恒花园
最后更新于 2026-03-23