大家都知道,我们临床数据分析的主力干将是SAS,SAS的主要功能是数据的清理和分析,是我们工作之本,但是,灵活使用一些其他的编程软件可以让计算机代替我们批量运行一些重复的操作,极大地提高工作效率。

所以Bunny今天就给大家介绍LINUX中的grep命令和for循环,这两个简单的命令可以帮助我们非常快捷地批量检查SAS log。

1. grep命令

grep命令是LINUX中的一种强大的文本搜索工具,它使用正则表达式搜索指定文本。大家可以把它类比为SAS中的prxmatch函数,与prxmatch函数不同的是,grep在搜索到指定文本后,可以同时输出指定文本所在的行。

grep命令的格式为:

grep [参数]

常用参数:

-i 忽略大小写

-o 只输出匹配到的部分,而非整个行

-v 反向选择,即输出没有没有匹配到的行

-E 同时匹配多个关键字/字符串

-n 在输出内容前加上对应行号

grep命令的基本格式就是这么简单,接下来,让我们用几个简单的例子试一试吧。Bunny使用的软件是mobaXterm。

查询对象是一个如下图所示的test.txt文件。

查找有连续a的行 grep grep循环查找_grep 与条件

首先使用cd命令进入所要查询的文件存放的文件夹。

查找有连续a的行 grep grep循环查找_查找有连续a的行 grep_02

接下来使用grep命令查询文件中是否有error这个单词。

查找有连续a的行 grep grep循环查找_查找有连续a的行 grep_03

运行结果如下:

查找有连续a的行 grep grep循环查找_for循环中gets_04

LINUX找到了test.txt文件中的单词“ERROR”,并输出了其所在行的所有文本。

让我们试试查找小写的单词“error”:

查找有连续a的行 grep grep循环查找_grep 多个关键字_05

这次LINUX没有返回任何结果,即表示test.txt文件中并没有单词“error”。

我们可以通过加上参数i来忽略大小写,加上n来同时输出行号,加上o来只输出匹配到的内容。

查找有连续a的行 grep grep循环查找_grep 与条件_06

此时的输出结果如下:

查找有连续a的行 grep grep循环查找_for循环中gets_07

成功匹配到单词“ERROR”,并且输出行号+匹配到的文本。

在我们检查SAS log时,往往要同时匹配多个文本,此时要用到grep命令的参数 -E 和正则表达式的元字符 | ,参数 -E 用来同时匹配多个关键字/字符串,元字符 | 用来将多个匹配条件用“或者”连接起来。grep命令如下图所示:

查找有连续a的行 grep grep循环查找_grep 与条件_08

此时可以同时查询文本“Invalid”和文本“Format was too small”,输出结果如下图所示:

查找有连续a的行 grep grep循环查找_grep 多个关键字_09

我们还可以使用“>>”命令将输出重定向到一个文件中,如:

查找有连续a的行 grep grep循环查找_for循环中gets_10

打开文件夹中的issue.txt文件,就可以看到我们查询到的关键文本。

查找有连续a的行 grep grep循环查找_grep 多个关键字_11

怎么样,grep命令是不是很简单。学到这里,我们就掌握了使用SHELL脚本检查SAS log的基本命令。

有的同学就要说了,这用grep命令也没比我在SAS里直接CTRL+F简单呀。是的,在检查单个文件时,LINUX并没有显示出它的优势,我们还需要一个小帮手来实现SAS log的批量查询,那就是for循环。

2. for循环

for循环的基本格式如下:

for X in XXX

do

command1

command2

...

commandN

done

和SAS里的do循环是很类似的,第一行的for语句决定了循环的对象和次数,即遍历XXX中的所有X,接下来对每一个X都执行do和done之间的命令。

检查SAS log时,我们所要进行的操作是遍历文件夹内的所有log文件,我们使用通配符*来匹配文件夹中的所有文件名,加上后缀.log就可以匹配出文件夹中的所有log文件,然后在do和done之间,写上grep命令,对每一个log文件都执行grep命令,如下图所示:

查找有连续a的行 grep grep循环查找_grep 多个关键字_12

${i}代表每次循环时对应的log文件名,此时LINUX会输出文件夹中所有log文件的包含grep命令中关键文本的行。如:

查找有连续a的行 grep grep循环查找_grep 与条件_13

此时,我们就做到了批量查询。但是每次都写这么大一段命令,未免有些太麻烦了,这时大家是不是想到了SAS中的宏程序呢?同样,在LINUX中,我们也可以将一段LINUX命令封装成一个文件,通过调用这个文件以及赋予文件参数来执行其中的LINUX命令,这就是SHELL脚本。

3. SHELL脚本

和SAS中的宏程序一样,SHELL脚本也是有参数的,这些参数在脚本文件内部可以使用$n的形式来接收。如,${1}代表第一个参数,${2}代表第二个参数。${0}是一个特殊的参数,它代表当前脚本的文件名。

首先,我们编辑如下图所示的一个SHELL脚本:

查找有连续a的行 grep grep循环查找_grep 与条件_14

其中的${1}就是我们调用时可以输入的参数,下面我们来调用这个SHELL脚本:

查找有连续a的行 grep grep循环查找_grep 两个字符串_15

用bash命令调用check_log.sh文件,输入的参数为issue3.txt,即将grep命令的结果输出重定向到issue3.txt文件中,下面是运行完成后的issue3.txt文件部分内容。

查找有连续a的行 grep grep循环查找_for循环中gets_16

此时我们的批量检查SAS log的SHELL脚本就初具雏形了,但是细心的同学可能会发现我们的脚本还有一个小问题,结果文件中的输出只有在原文件中的行号,而没有具体的文件名,我们无法从结果文件中得到每一条issue log对应的是哪一个log文件。

为了解决这个问题,我们可以在每次输出issue log之前,使用echo命令输出查询的文件名,并重定向到汇总log的文件中,用于提示后面查询到的issue log的来源。如下图所示:

查找有连续a的行 grep grep循环查找_for循环中gets_17

此时我们的结果为:

查找有连续a的行 grep grep循环查找_for循环中gets_18

此时我们的SHELL脚本就可以方便快捷地批量查询SAS log,并将文件名,行号以及关键词所在行内容输出到指定文件中,方便我们对每一条issue log进行定位啦。

通过今天的分享,大家有没有发现我们的工作小助手并不是只有SAS呢,其实,不仅仅是SHELL脚本,其他的编程软件,如python,VBA,R,都可以在某些方面极大地提高我们的工作效率,解放双手呢。所以,一定不要只是埋头在SAS里,工作之余,学学其他软件,可能会有意想不到的收获!