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,虽然也可以使用==和=,但本质上是字符串比较,对于010和10数值上相等(可能还会由于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
此外,NF在awk中可以表示列的个数,如给定:
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中

Comments NOTHING