linux shell遍历当前文件夹中的txt文件并处理生成新的文件

问题描述:当前文件夹中有a.txt,b.txt,c.txt,d.txt 等文件,且这些txt文件中的某些行包含有关键字《keywords》和《/keywords》,他们之间包含有其他字符串(注:《keywords》和《/keywords》不一定在同统一行)
要求:分别从这些txt文件中将《keywords》。。。《/keywords》中所有字符串原封不动的分别追加到文件夹 ./newfile中的四个文件,即./newfile/a.txt,./newfile/b.txt,./newfile/c.txt,./newfile/d.txt。
比如说a.txt中为:
fdjs sdfsdfs
《keywords》sdkfjsd《/keywords》
aflsdfsd
《keywords》dsdgfsd
dsfd《/keywords》
那么处理后在./newfile/a.txt中保存为:
《keywords》sdkfjsd《/keywords》
《keywords》dsdgfsd
dsfd《/keywords》
跪求高人指点,感激不尽!!!

先以a.txt为例:

awk -v RS="" '{ 
n = split($0,a,"《[^》]+》");
for(i=2;i<n;i+=2)
    print "《keywords》"a[i]"《/keywords》" 
}' a.txt >>./newfile/a.txt

这样就行了。

为了可读性,我将一条awk语句写成了多行。

 

实际测试结果如下:

 

解说:

RS=""

将awk的记录分隔符设置为空(默认是换行符),即将整个a.txt文本看做一条记录。

n = split($0,a,"《[^》]+》");

以正则"《[^》]+》"匹配的内容作为分隔符,对文本内容进行分割并将分割结果存入数组a,分割出的数目(数组大小)即为split函数的返回值n。这里暂且不对该正则做过多解释,否则喧宾夺主,有需要请追问,我再补充。

for(i=2;i<n;i+=2)
    print "《keywords》"a[i]"《/keywords》"

打印数组下标为偶数的元素并在首尾分别加上关键字标记以还原。数组下标从1开始。

 

其他文件可作相同处理。如果文件较多,你可以搞个循环去做。这个应该不难。

追问

如何循环读取当前文件夹中的所有.txt文件?一直没找到这样的例子。

追答

这种应用其实很常见。

for ofile in *.txt
do
    awk -v RS="" '{n=split($0,a,"《[^》]+》");for(i=2;i<n;i+=2)print "《keywords》"a[i]"《/keywords》"}' $ofile >>./newfile/$ofile
done

 

*.txt 就代表当前目录下所有txt文件的一个集合。

*在这里是通配符,shell解释器会将其自动展开。

追问

非常感谢,不过还有一些疑问:

如果说a.txt中含有多对关键字(《keywords1》《keywords1》,《keywords2》《keywords2》),且关键字所包含的字符串都追到./newfile/a.txt中,这样改可以吗?

若文件中包含“《》,《/》”这种字符串,你那种写法会过滤他们吗?

追答

要掌握正则表达式需要花一些功夫,可以去看看网上的《正则表达式30分钟入门教程》。
split函数根据正则表达式《[^》]+》分割文本字符串。
[^》] 表示不为》的任意一个字符。
+表示重复前面这个字符1次或多次,*表示重复前面这个字符0次或多次。
因此,若文件中包含“《》,《/》”这种字符串,可以将+改为*。

正则中,由于+和*都具有贪婪的特性,即总是会最大匹配。拿下面这行文本举例来说:
《keywords》sdkfjsd《/keywords》
《.*》或《.+》会匹配整行文本,而《[^》]+》或《[^》]*》就只能匹配《keywords》或《/keywords》。为了防止匹配到后面一个》,所以这里限定了匹配的字符不为》,即[^》]。

慢慢体会吧。
看懂正则可能不是那么难,但要真正掌握却不是短时间的事,我都不敢说我真正掌握了。

温馨提示:答案为网友推荐,仅供参考