我的 ASCII 文件是这样的:
a
1 2 3
1223
b
1 2 3 5
3344
1223
c
1 2 34
a
4 5
c
123
如何分别收集 a、b、c 下面的行?
问:我该怎么做才能得到下面的几行?
a
1 2 3
1223
4 5
答案1
awk '/^[a-z]$/ { f = $1=="a" ; if (!c++) print ; next }; f'
答案2
啊,awk
与我迄今为止在这里看到的其他解决方案不同,仅使用一次数据传递,使事情变得更加容易:
/^[a-z]/{key=$0;}
/^[0-9]/{if (key in res){ res[key]=res[key] "\n" $0;} else {res[key]=$0;}}
END {for(key in res){
print key;
print res[key];
}}
如果你想要sed
+frills-only,这似乎有效:
cat data.txt | sed -e '/^a/,/^[b-z]/!d' | sed -e '2,${ /^[a-z]/d }'
(是的,这是一个对猫的无用利用 出于教学原因,即当文件位于管道中间的某个位置时,我会感到困惑。)
第一个考虑以字母 开头的行sed
开头和结尾的所有范围(包括)。它否定该范围(the ),然后删除所有匹配的内容,所以我们只剩下a
b-z
!
a
1 2 3
1223
b
a
4 5
c
第二个sed
仅查看从第 2 行到文件末尾的范围(以维护标题a
),并在其中删除所有以字母 开头的行a-z
,只留下数字行:
a
1 2 3
1223
4 5
要获取所有标题的列表,我会尝试grep '^[a-z]' | sort -u
。所以整个野兽是:
for key in $(grep '^[a-z]' data.txt | sort -u ); do
cat data.txt | sed -e "/^$key/,/^[b-z]/\!d" | sed -e '2,${ /^[a-z]/d }' ;
done
答案3
awk '
/^[a-z]$/{
i=$0
next
}
{
A[i]=A[i] "\n" $0
}
END{
for (j in A)
print j A[j]
}'
正如你所看到的,它是以下的简化变体@Ulrich Schwarz 脚本:对于仅包含 1 个小写字母的行,将此字母作为索引i
并开始新行循环。接下来,A
根据i
脚本前一部分使用\n
ewline 分隔符确定的索引,将所有剩余行(不是“仅包含 1 个小写字母”,因为它之前已操作过)放入关联数组中。当脚本传递所有行(到达)时,然后按索引END
打印数组。A
i
答案4
这是一个awk
不遗余力防止打印第二个的解决方案a
:
awk '$1 == "a" { if (!head) print; n=head=1; next } $1 !~ /^[0-9]/ { n=0 } n' ascii_file
替换"a"
为"b"
以获得这些结果等。
输出:
a
1 2 3
1223
4 5
如果你想要一个循环,你可以这样做:
for letter in a b c; do
echo
awk -v letter="$letter" '$1 == letter { if (!head) print; n=head=1; next } $1 !~ /^[0-9]/ { n=0 } n' /tmp/a
done
会有这样的输出:
a
1 2 3
1223
4 5
b
1 2 3 5
3344
1223
c
1 2 34
123
(注意这一echo
行。它在每个查询的命中之间进行分隔。我构建这个答案是为了让您可以按字母查询,这是我对这个问题的理解。)