我想使用以下awk行删除文本文件中的每个偶数行(并保留奇数行)。
awk 'NR%2==1' filename.txt > output
问题是我很难在awk中正确循环或者构建一个shell脚本以将其应用于文件夹中的所有* .txt文件。我试着用这个单线
gawk 'FNR==1{if(o)close(o);o=FILENAME;
sub(/\.txt/,"_oddlines.txt",o)}{NR%2==1; print>o}'
但是没有删除偶数行。我对shell脚本更不熟悉了。我在gawk
下使用win7
或cygwin
使用bash
。非常感谢任何想法。
答案 0 :(得分:3)
你现有的gawk单线非常接近。在这里,它被格式化为更易读的脚本:
FNR == 1 {
if (o)
close(o)
o = FILENAME
sub(/\.txt/, "_oddlines.txt", o)
}
{
NR % 2 == 1
print > o
}
这应该使错误明显 1 。现在我们删除该错误:
FNR == 1 {
if (o)
close(o)
o = FILENAME
sub(/\.txt/, "_oddlines.txt", o)
}
NR % 2 == 1 {
print > o
}
$ awk -f foo.awk *.txt
并且它有效(当然你可以重新整理这个)。
(通常情况下,我会像其他答案那样使用for
这样做,但我想告诉你你有多接近!)
1 每条评论,也许不是那么明显?
Awk的基本语言构造是“模式 - 动作”语句。 awk 程序只是这些语句的列表。 “模式”是如此命名的,因为它们最初主要是类似grep的正则表达式模式:
$ awk '/^be.*st$/' < /usr/share/dict/web2
beanfeast
beast
[snip]
(除了斜杠,这基本上只是运行grep
,因为它使用默认操作print
。)
模式实际上可以包含两个地址,但在这些情况下使用一个地址更为典型。未包含在斜杠中的模式允许执行FNR == 1
(F
ile特定N
此R
ecord等于1
)或NR % 2 == 1
的测试(所有文件中N
ecord-cumulative的R
数字!-mod 2
等于1
)。
然而,一旦你击中了开放式支撑,你就会进入“动作”部分。现在NR % 2 == 1
只计算结果(true或false),然后将其抛弃。如果完全省略“pattern”部分,则“action”部分将在每个输入行上运行。所以这会打印每一行。
请注意,测试NR % 2 == 1
正在测试累积记录号。因此,如果某个文件具有奇数行(“记录”),则下一个文件将打印出每个偶数行(并且这将持续到您使用奇数行搜索另一个文件)。
例如,假设两个输入文件是A.txt
和B.txt
。 Awk开始阅读A.txt
并且第一行的FNR
和NR
都设置为1,例如file A, line 1
。自FNR == 1
第一个“操作”完成后,设置o
。然后awk测试第二个模式。 NR
为1,因此NR % 2
为1,因此第二个“操作”完成,将该行打印到A_oddlines.txt
。
现在假设文件A.txt
只包含那一行。 Awk现在继续提交B.txt
,重置FNR
但累计NR
。 B
的第一行可能是file B, line 1
。 Awk尝试第一个“模式”,实际上是FNR == 1
,因此关闭旧的o
并设置新的模式。
但NR
为2
,因为NR
在所有输入文件中累积。因此,第二个模式(NR % 2 == 1
)计算2 % 2
(0
)并比较== 1
,这是假的,因此awk跳过第1行的第二个“动作”档案B.txt
。第2行(如果存在)将包含FNR == 2
和NR == 3
,因此该行将被复制出来。
(我最初假设,因为你的脚本已经接近工作了,你打算这样做,而且只是在语法上留了一点。)
答案 1 :(得分:3)
使用GNU awk
,您可以这样做:
$ awk 'FNR%2{print > (FILENAME".odd")}' *.txt
这将为当前目录中仅包含奇数行的每个.odd
文件创建一个.txt
文件。
然而sed
在这里简洁明了。以下GNU sed
命令将删除所有偶数行,并为当前目录中的所有.bck
文件存储扩展名为.txt
的旧文件:
$ sed -ni.bck '1~2p' *txt
<强>演示:强>
$ ls
f1.txt f2.txt
$ cat f1.txt
1
2
3
4
5
$ cat f2.txt
6
7
8
9
10
$ sed -ni.bck '1~2p' *txt
$ ls
f1.txt f1.txt.bck f2.txt f2.txt.bck
$ cat f1.txt
1
3
5
$ cat f1.txt.bck
1
2
3
4
5
$ cat f2.txt
6
8
10
$ cat f2.txt.bck
6
7
8
9
10
如果你不支持备份文件,那么只需:
$ sed -ni '1~2p' *txt
答案 2 :(得分:1)
您可以尝试for循环:
#!/bin/bash
for file in dir/*.txt
do
oddfile=$(echo "$file" | sed -e 's|\.txt|_odd\.txt|g') #This will create file_odd.txt
awk 'NR%2==1' "$file" > "$oddfile" # This will output it in the same dir.
done
答案 3 :(得分:1)
就个人而言,我会使用
for filename in *.txt; do
awk 'NR%2==1' "$filename" > "oddlines-$filename"
done
编辑:引用文件名
答案 4 :(得分:1)
您的问题是NR%2==1
位于{NR%2==1; print>o}
'操作区'内,并没有作为'条件'开始。请改用:
gawk 'FNR==1{if(o)close(o);o=FILENAME;sub(/\.txt/,"_oddlines.txt",o)};
FNR%2==1{print > o}' *.txt