cndaqiang Web Linux DFT

文件处理: grep sed awk sort echo printf tail cut paste

2018-10-17
cndaqiang
RSS

原文正则表达式 文件格式处理 shell脚本
gitbook访问太慢了,重置文章到此处




正则表达式

定义

正则表达式通常被用来检索、替换那些匹配某个模式的文本
不仅在linux命令中使用,在php,python等语言和notepad++等文本编辑器中也经常用于快速检索某串字符

语系对正规表示法的影响

不同语系的编码数据并不相同,如

  • LANG=C 时:0 1 2 3 4 … A B C D … Z a b c d …z
  • LANG=zh_TW 时:0 1 2 3 4 … a A b B c C d D … z Z

当我们使用[A-Z]提取正则表达式时,对LANG=C提取是A-Z的所有大写字母,而LANG=Zh_TW提取A-Z和a-z
不过在linux等常用情况都默认是LANG=C语系,我们不用了解太多

语法

先看下具体规则,再对vasp输出文件进行处理

特殊符号

感觉这个不是很常用 image.png

基础正规表示法字符汇整

这个好记忆,而且好用 image.png

高级用法

有点用处
注意鸟哥给的示例使用的是egrap,grep是不支持这些语法的 image.png

grep

语法

grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,默认大小写不同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
--color=auto :可以将找到的关键词部分加上颜色的显示喔!

示例

以我用vasp计算时某次结构优化后某OUTCAR为例
下载地址https://cndaqiang.github.io/web/file/2018/sf10/linux/OUTCAR
下载命令

wget https://cndaqiang.github.io/web/file/2018/sf10/linux/OUTCAR

使用此OUTCAR文件进行下列示例

$ grep "E-fermi" OUTCAR
#搜索计算的费米能级
 E-fermi :  -1.7694     XC(G=0):  -4.2437     alpha+bet : -3.6065
 E-fermi :  -1.6967     XC(G=0):  -4.2322     alpha+bet : -3.6065
 E-fermi :  -1.7565     XC(G=0):  -4.2059     alpha+bet : -3.6065
 E-fermi :  -1.8226     XC(G=0):  -4.2557     alpha+bet : -3.6065
 E-fermi :  -1.5143     XC(G=0):  -4.0949     alpha+bet : -3.6065
 E-fermi :  -1.4183     XC(G=0):  -4.0606     alpha+bet : -3.6065
 E-fermi :  -1.4229     XC(G=0):  -4.1155     alpha+bet : -3.6065
 E-fermi :  -1.4078     XC(G=0):  -4.1161     alpha+bet : -3.6065
$ grep -c "E-fermi" OUTCAR
8
$ grep -ci "E-fermi" OUTCAR
8
$ grep -cn "E-fermi" OUTCAR
#有参数c时,只输出结果数,不输出结果
8
$ grep -n "E-fermi" OUTCAR
#输出行号
1956: E-fermi :  -1.7694     XC(G=0):  -4.2437     alpha+bet : -3.6065
3601: E-fermi :  -1.6967     XC(G=0):  -4.2322     alpha+bet : -3.6065
5451: E-fermi :  -1.7565     XC(G=0):  -4.2059     alpha+bet : -3.6065
7351: E-fermi :  -1.8226     XC(G=0):  -4.2557     alpha+bet : -3.6065
9201: E-fermi :  -1.5143     XC(G=0):  -4.0949     alpha+bet : -3.6065
10852: E-fermi :  -1.4183     XC(G=0):  -4.0606     alpha+bet : -3.6065
12007: E-fermi :  -1.4229     XC(G=0):  -4.1155     alpha+bet : -3.6065
13113: E-fermi :  -1.4078     XC(G=0):  -4.1161     alpha+bet : -3.6065

因为我结构优化时,驰豫了8次离子步,所以有8个结果

grep支持正则表达式

特殊符号示例

$ grep "[:alpha:]-fermi" OUTCAR
grep: 字符类的语法是 [[:space:]],而非 [:space:]
$ grep "[[:alpha:]]-fermi" OUTCAR
 E-fermi :  -1.7694     XC(G=0):  -4.2437     alpha+bet : -3.6065
 E-fermi :  -1.6967     XC(G=0):  -4.2322     alpha+bet : -3.6065
 E-fermi :  -1.7565     XC(G=0):  -4.2059     alpha+bet : -3.6065
 E-fermi :  -1.8226     XC(G=0):  -4.2557     alpha+bet : -3.6065
 E-fermi :  -1.5143     XC(G=0):  -4.0949     alpha+bet : -3.6065
 E-fermi :  -1.4183     XC(G=0):  -4.0606     alpha+bet : -3.6065
 E-fermi :  -1.4229     XC(G=0):  -4.1155     alpha+bet : -3.6065
 E-fermi :  -1.4078     XC(G=0):  -4.1161     alpha+bet : -3.6065

基础正规表示法字符示例

查看最终是否收敛,收敛时,OUTCAR内会有reached required accuracy - stopping structural energy 这句,我们搜索reached
我们发现有很多,可以采用以 reached为开头搜索

$ grep "reached" OUTCAR
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
------------------------ aborting loop because EDIFF is reached ----------------------------------------
 reached required accuracy - stopping structural energy minimisation
 $ grep "^ reached" OUTCAR
 reached required accuracy - stopping structural energy minimisation
#.表示一定有一个字节
$ grep "^ r.ached" OUTCAR
 reached required accuracy - stopping structural energy minimisation

egrep示例高级语法

能搜到的太多了,我就只显示行数了,可以看到?(零个或1个)比+(至少1个)搜到的结果多

$ egrep -c "[0-9]+" OUTCAR 
9858
$ egrep -c "[0-9]?" OUTCAR 
13956

读取代码/配置跳过行首为#的注释行

#去除#号开头
grep StateSaveLocation /etc/slurm-llnl/slurm.conf  | grep -v "^ *#"
root@mommint:/opt# grep StateSaveLocation /etc/slurm-llnl/slurm.conf  | grep -v "^ *#"
StateSaveLocation=/var/spool/slurm-llnl

提取空格开头,首单词确定的行

(python37) [HUAIROU cndaqiang@login01 0.00015y_y0_0.117_ramdom10k]$grep ^[[:blank:]]*temperature result | head -3
     temperature           =         106.78531944 K
     temperature           =         114.58036450 K
     temperature           =         149.09400799 K

更多示例

鸟哥给的示例,下载地址https://cndaqiang.github.io/web/file/2018/sf10/linux/regular_express.txt

grep_OUTCAR
grep_POTCAR.md


报错

Binary file result matches

也许是因为文件太大的原因, 文本文件被识别为二进制文件, 添加-a 参数

(python37) [HUAIROU cndaqiang@login01 edt0.5RunNVE0_nofield]$grep MD result
Binary file result matches
(python37) [HUAIROU cndaqiang@login01 edt0.5RunNVE0_nofield]$grep -a MD result  | head -1
     MD5 check sum: 7de1f3f262afbb95e2ae740af32c06ec

sed

功能

对文件增加,替换,删除,插入,打印等命令
以行为处理单位

语法

sed支持管道语法

[root@www ~]## sed [-nefr] [动作] 文件名/管道输入
选项与参数:
-n  :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 
      的数据一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过
      sed 特殊处理的那一行(或者动作)才会被列出来。
-e  :直接在命令列模式上进行 sed 的动作编辑;
-f  :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 
      sed 动作;
-r  :sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)
-i  :直接修改读取的文件内容,而不是由萤幕输出。

动作说明:  [n1[,n2]]function
n1, n2 :不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作
         是需要在 10 到 20 行之间进行的,则『 10,20[动作行为] 』

function 有底下这些咚咚:
a   :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c   :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d   :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i   :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p   :列印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
s   :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配
      正规表示法!例如 1,20s/old/new/g 就是啦!

鸟哥:sed 后面接的动作,请务必以 ‘’ 两个单引号括住喔!

示例

选项参数

-n只显示处理的行

$ ls
ls.txt  nohup.out  OUTCAR
#在原来的第2,3行前插入hello
$ ls |sed '2,3ihello'
ls.txt
hello
nohup.out
hello
OUTCAR
$ ls |sed -n '2,3ihello'
hello
hello

-e是默认的,直接输入动作,-f 文件名,从文件中读入动作命令

#将命令保存到sedfile文件
$ echo 2,3ihello word >sedfile
## -f 调用文件
$ ls |sed -f sedfile 
ls.txt
hello word
nohup.out
hello word
OUTCAR
sedfile

-i 不显示在屏幕上

鸟哥:这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!透过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!很棒吧!

$ ls > ls_out_file
$ cat ls_out_file 
ls_out_file
ls.txt
nohup.out
OUTCAR
sedfile
$ sed -i -f sedfile ls_out_file 
$ cat ls_out_file 
ls_out_file
hello word
ls.txt
hello word
nohup.out
OUTCAR
sedfile

动作参数

去除行行尾的空格和tab

cat XXX | sed 's/[ \t]*$//g' | sed 's/^[ \t]*//g'

举一个取代的例子,语法:

sed 's/要被取代的字串/新的字串/g'

我们测试晶格常数时,可以使用sed批量替换成POSCAT
https://cndaqiang.github.io/web/file/2018/sf10/linux/POSCAR

$ cat POSCAR 
CoCl2 Vaccum=15
1.0
        3.5269000530         0.0000000000         0.0000000000
       -1.7634500265         3.0543850425         0.0000000000
        0.0000000000         0.0000000000        17.6408996582
   Co   Cl
    1    2
Direct
     0.000000000         0.000000000         0.074850000
     0.666670032         0.333329992         0.000000000
     0.333329986         0.666669976         0.149700000
$ cat POSCAR |sed '2s/1.0/1.1/g' >POSCAR1.1 
$ cat POSCAR1.1 
CoCl2 Vaccum=15
1.1
        3.5269000530         0.0000000000         0.0000000000
       -1.7634500265         3.0543850425         0.0000000000
        0.0000000000         0.0000000000        17.6408996582
   Co   Cl
    1    2
Direct
     0.000000000         0.000000000         0.074850000
     0.666670032         0.333329992         0.000000000
     0.333329986         0.666669976         0.149700000

其他

sed -n "1~${eachstep}p" input
从第1行开始,每隔eachstep行,进行输出。

问题

推荐使用双引号

双引号能识别变量$变量名,单引号不识别变量

修改某个文件

错误做法

cat $global |sed "8s/${olduser}/${newuser}/g"  > $global 

应该

sed -i "8s/${olduser}/${newuser}/g" $global




awk

功能

相较于 sed以行为处理单位, awk 则把一行分成数个小单位来处理。

语法

awk支持管道命令

awk '条件类型1{动作1} 条件类型2{动作2} ...' filename

特殊字符转移

替换](/in](/out/),即替换markdown的url

    sed -i s/\]\(\\/${in}/\]\(\\/${out}\\//g $i
    sed -i s/\]\(\\/\\//\]\(\\//g $i

使用\) \] \\( \\[ \\/分别转义) ] ( [ /

变量

awk内建变量

变量名称 意义
NF 每一行分成的单元数
NR 目前 awk 所处理的是第几行数据
FS 目前的分隔字节,默认是空白键
$n 当前行的第n个单元

print后面默认只能识别内建变量,使用-v指定自定义变量, 可用于循环提取每一列的各值, 如原子坐标

echo "hello world" |awk -vorder=2 '{ print $order }'
world

条件类型

逻辑类型 意义
> 大于
< 小于
>= 大于或等于
<= 小于或等于
== 等于
!= 不等于
&&
\\

注意等于是==

动作

  • print $1,$2
  • printf "%f %f\n", $1,$2 需要自己添加换行符\n

示例

以#开头的

awk '/#/' file.out

跳过#开头

awk '!/#/' file.out

跳过#开头并输出第6个

awk '!/#/{ print $6}' file.out

从POSCAR中,提取3到5行,设置分隔符为” “,
awk的printf动作和printf有点不同,printf "格式控制",变量,变量,使用逗号隔开变量

$ cat POSCAR
CoCl2 Vaccum=15
1.0
        3.5269000530         0.0000000000         0.0000000000
       -1.7634500265         3.0543850425         0.0000000000
        0.0000000000         0.0000000000        17.6408996582
   Co   Cl
    1    2
Direct
     0.000000000         0.000000000         0.074850000
     0.666670032         0.333329992         0.000000000
     0.333329986         0.666669976         0.149700000
$ sed -n 3,5p POSCAR
        3.5269000530         0.0000000000         0.0000000000
       -1.7634500265         3.0543850425         0.0000000000
        0.0000000000         0.0000000000        17.6408996582
#\表示换行继续输入
$ sed -n 3,5p  POSCAR | awk '{FS=" "} (($1!=0 && $2==0)||$1==0) \
> {printf "%f\t%f\tNF=%i\tNR=%i\tFS=%s__\n",$1,$2,NF,NR,FS}'
3.526900	0.000000	NF=3	NR=1	FS= __
0.000000	0.000000	NF=3	NR=3	FS= __

从OUTCAR中提取费米能级
tail -1表示最后一行,之前秋豪讲过

$ grep  "E-fermi" OUTCAR
\ E-fermi :  -1.7694     XC(G=0):  -4.2437     alpha+bet : -3.6065
 E-fermi :  -1.6967     XC(G=0):  -4.2322     alpha+bet : -3.6065
 E-fermi :  -1.7565     XC(G=0):  -4.2059     alpha+bet : -3.6065
 E-fermi :  -1.8226     XC(G=0):  -4.2557     alpha+bet : -3.6065
 E-fermi :  -1.5143     XC(G=0):  -4.0949     alpha+bet : -3.6065
 E-fermi :  -1.4183     XC(G=0):  -4.0606     alpha+bet : -3.6065
 E-fermi :  -1.4229     XC(G=0):  -4.1155     alpha+bet : -3.6065
 E-fermi :  -1.4078     XC(G=0):  -4.1161     alpha+bet : -3.6065
$ grep  "E-fermi" OUTCAR |awk '{printf "%f\n",$5}'
-4.243700
-4.232200
-4.205900
-4.255700
-4.094900
-4.060600
-4.115500
-4.116100
$ grep  "E-fermi" OUTCAR |awk '{printf "%f\n",$5}'|tail -1
-4.116100

从siesta输出提取偶极矩
$(NF-1)表示倒数第二列

grep  "Electric dipole (a.u.)" result | awk '{printf "%f\t%f\t%f\n", $(NF-2),$(NF-1),$NF }' > dipole

补充应用

awk求和求平均

cat count.txt | awk '{sum+=$1} END {print "Average = ", sum}'
cat count.txt | awk '{sum+=$1} END {print "Average = ", sum/NR}'
grep -v "#" simulation.out  |  awk '{sum+=$6} END {printf "Average = %1.10e \n", sum/NR}'

方差

col=$(grep $phy $i    | awk '{ print $3+1 }')
mean=$(grep -v "#" $i | awk '{sum+=$'$col'} END {printf "%1.10e", sum/NR}')
#注意mean前面不能有空格,不然下面的'$mean'会报错
std=$(grep -v "#" $i | awk '{sum+=($'$col' - '$mean')**2 } END {printf "%1.10e", sqrt(sum/(NR-1))}')
echo $i $phy mean=$mean std=$std

最大/小值

tail -n +$startline $INPUTFILE | awk 'BEGIN {max = 0} {if ($2+0 > max+0) max=$2} END {print "Max=", max}'
tail -n +$startline $INPUTFILE | awk 'BEGIN {min = 9999999} {if ($2+0 < min+0) max=$2} END {print "Min=", min}'
#同时求最大最小, BEGIN和END的用法
tail -n +$startline $INPUTFILE | awk 'BEGIN {max = -9999; min=9999} {if ($2+0 > max+0) max=$2; if ($2+0 < min+0) min=$2 } END {printf "%15.10f,%15.10f \n" , max, min }' 

awk中使用系统变量

使用'$var'分隔开即可,注意var可以var=6但是不可以是var=' 6',即不能有空格
可以使用循环生成var=",$3,$5,$6",但是var中绝对不能出现空格

col=6
grep -v "#" simulation.out  |  awk '{sum+=$'$col'} END {printf "Average = %1.10e \n", sum/NR}'

awk print单引号

用单引号隔开,在用转义字符即可,"'\''%s'\''"内部一定不要有空格!!!

tail -n +$startline $INPUTFILE | awk '{printf "'\''%s'\''",$1}'

awk的计算功能

(python37) cndaqiang@mommint:~$ echo | awk '{ print sin(3.141592653/2) , cos(3.141592653/2) }'
1 2.94897e-10

awk在每行内添加值

如每行首添加行号

 awk '{print NR,"\t",$0  }' 3,3,3

awk将修改结果直接写入文件

错误示范,下面这种方式,只写入了几行,后面的数据都没有了

awk '{print NR,"\t",$0 > "3,3,3" }' 3,3,3

awk提取特定文字之间的内容

提取Begin PSP_UPFEND_PSP之间的内容

awk 'Begin{out=0};/END_PSP/{out=0}; {if(out == 1) {print}};\
        /Begin PSP_UPF/{out=1}' $OUTFILE >$TEMP




echo

功能

echo是Shell的一个内部指令,用于在屏幕上打印出指定的字符串。
不支持管道

语法

echo [-e]"要打印内容"

echo默认是禁用反斜杠转义功能的,开启使用-e参数

       \\    反斜杠
       \a    警告声音输出
       \b    倒退键(backspace)
       \f    清除屏幕 (form feed),(换页(FF),将光标移到下页开头)
       \n    输出新的一行(光标移到下行开头)
       \r    亦即 Enter 按键(光标回到当前行开头)
       \t    水平的 [tab] 按键
       \v    垂直的 [tab] 按键

示例

使用转移字符,需加上-e参数,最好使用双引号

$ pi=3.1415926
## 双引号可以省略,支持变量,单引号会直接输出所有内容
$ echo "$pi"
3.1415926
$ echo '$pi'
$pi
$ echo $pi
3.1415926
## 使用转移字符,需加上-e参数,最好使用双引号
$ echo $pi\t\v$pi
3.1415926tv3.1415926
$ echo -e $pi\t\v$pi
3.1415926tv3.1415926
$ echo -e "$pi\t\v$pi"
3.1415926	
                3.1415926
$ echo -e '$pi\t\v$pi'
$pi	
        $pi

不换行-e "str\c"

[cndaqiang@mgmt output_iter]$ for i in $(seq 1 20); do echo -e "$i,\c"; done | xargs
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,




printf

功能

printf 命令用于格式化输出, 是echo命令的增强版。它是C语言printf()库函数的一个有限的变形,并且在语法上有些不同。
不支持管道

语法

printf '列印格式' 实际内容
选项与参数:
关於格式方面的几个特殊样式:
       \a    警告声音输出
       \b    倒退键(backspace)
       \f    清除屏幕 (form feed),(换页(FF),将光标移到下页开头)
       \n    输出新的一行(光标移到下行开头)
       \r    亦即 Enter 按键(光标回到当前行开头)
       \t    水平的 [tab] 按键
       \v    垂直的 [tab] 按键
       \xNN  NN 为两位数的数字,可以转换数字成为字节。
关於 C 程序语言内,常见的变量格式
       %ns   那个 n 是数字, s 代表 string ,亦即多少个字节;
       %ni   那个 n 是数字, i 代表 integer ,亦即多少整数码数;
       %N.nf 那个 n 与 N 都是数字, f 代表 floating (浮点),如果有小数码数,
             假设我共要十个位数,但小数点有两位,即为 %10.2f 罗!

示例

pi=3.1415926
$ printf '%f\n%f' $pi $pi
3.141593
3.141593$ printf '%f\n%f\n' $pi $pi
3.141593
3.141593
## \r会,回到该列开头进行覆盖
$ printf '%f\n%2.1f\n' 123 4
123.000000
4.0
$ printf '%f\r%2.1f\n' 123 4
4.0.000000
#\t制表符,用来对齐,\v垂直制表,回车加制表
$ printf '%f\t%f\v%f\n' 3 3 3
3.000000	3.000000
                    3.000000

整数前置补0,如octopus的输出

for i in $(seq 0 50 13000); do  echo $(printf "td.%07d\n" $i); done

sort排序

sort -n按数字排序,-rn反向数字排序

(python37) cndaqiang@mommint:~/work/tdpw/wannier-h2o-2020-12-18/MD/wannier/test$ ls |sort
10.vasp
11.vasp
20.vasp
2.vasp
(python37) cndaqiang@mommint:~/work/tdpw/wannier-h2o-2020-12-18/MD/wannier/test$ ls |sort -n
2.vasp
10.vasp
11.vasp
20.vasp
(python37) cndaqiang@mommint:~/work/tdpw/wannier-h2o-2020-12-18/MD/wannier/test$ ls |sort -rn
20.vasp
11.vasp
10.vasp
2.vasp

tail

从第5行开始

tail -n +5

倒数5行

tail -5

cut切文件

3. 文本处理

  • 截取文件的第2列和第4列
    cut -f2,4 filename
    
  • 去文件除第3列的所有列
    cut -f3 --complement filename
    
  • -d 指定定界符
    cat -f2 -d";" filename
    
  • cut 取的范围
    • N- 第N个字段到结尾
    • -M 第1个字段为M
    • N-M N到M个字段
  • cut 取的单位
    • -b 以字节为单位
    • -c 以字符为单位
    • -f 以字段为单位(使用定界符)

示例:

cut -c1-5 file //打印第一到5个字符
cut -c-2 file  //打印前2个字符

截取文本的第5到第7列

$echo string | cut -c5-7

paste合并文件

(python37) cndaqiang@mommint:~$ cat 1
1
2
3
(python37) cndaqiang@mommint:~$ cat 2
2
3
(python37) cndaqiang@mommint:~$ paste 1 2
1	2
2	3
3

和awk连用可以进行计算和提取数据

(python37) cndaqiang@mommint:~$ paste 1 2 | awk '{print $2*10, ($1+$2)/2}'
20 1.5
30 2.5
0 1.5

本文首发于我的博客@cndaqiang.
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!



评论


广告

目录

广告
访客数据