我的输入文件是file_1.txt
、file_2.txt
、file_3.txt
等等。这些文件包含以下数据
$ head log_file_reset_*.txt
==> file_1.txt <==
Test #1
data
Test #2
data
Test #3
Test #4
data
==> file_2.txt <==
Test #1
Test #2
data
Test #3
Test #4
data
==> file_3.txt <==
Test #1
data
Test #2
data
Test #3
Test #4
仅当输入文件中Test
每个数据下的可用数据为以下情况时,我现在拥有的代码才能获取后面的序列号:Test
#!/bin/bash
#################################################################################################
CWD=$(pwd)
for j in {1..5}
do
sed -n '
/^Test #/ {
s///
=
p
}
$=
' file_$j.txt \
| paste - - \
| awk -F '\t' '
NR > 1 && $1 - prevLine > ($2 ? 2 : 0) {print prev}
{prevLine = $1; prev = $2}
' >> 1_val.txt
我从这段代码中得到的输出存储在1_val.txt
:
1_val.txt
1
2
4
2
4
1
2
我可以知道如何修改代码以获得列出的数据的文件名(只是数字)1_val.txt
并将其存储在另一个名为 的文件中2_val.txt
吗?
预期输出:
2_val.txt
1
1
1
2
2
3
3
答案1
当您使用 awk 时,您永远不需要 sed。下面是你真正应该如何做你的问题中的 shell 脚本所做的事情(我能说的最好的),在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ cat tst.awk
FNR==1 {
testId = ""
}
testId != "" {
if (NF) {
print testId
}
testId = ""
}
sub(/^Test #/,"") {
testId = $0
}
$ awk -f tst.awk file_*.txt
1
2
4
2
4
5
1
2
然后将上述内容打印到 1 个输出文件并将文件号打印到另一个输出文件只需进行以下调整:
$ cat tst.awk
FNR==1 {
testId = ""
split(FILENAME,f,/[_.]/)
fileId = f[2]
}
testId != "" {
if (NF) {
print testId > "1_val.txt"
print fileId > "2_val.txt"
}
testId = ""
}
sub(/^Test #/,"") {
testId = $0
}
$ awk -f tst.awk file_*.txt
$ head *_val.txt
==> 1_val.txt <==
1
2
4
2
4
5
1
2
==> 2_val.txt <==
1
1
1
2
2
2
3
3
编辑以解决OP中的以下评论:如果您不希望将其存储在单独的文件中,则以下是如何在shell脚本中内联使用上述awk脚本:
$ cat tst.sh
#!/usr/bin/env bash
awk '
FNR==1 {
testId = ""
split(FILENAME,f,/[_.]/)
fileId = f[2]
}
testId != "" {
if (NF) {
print testId > "1_val.txt"
print fileId > "2_val.txt"
}
testId = ""
}
sub(/^Test #/,"") {
testId = $0
}
' "${@:--}"
然后你可以将 shell 脚本称为:
$ ./tst.sh file_*.txt
答案2
如果你有 GNU sed ,可以像这样完成:
sed -nsE '
/#/N;/\n./F
s/.*#([0-9]+)\n.+/\1/w1_val.txt
' file_?*.txt |
sed '/\n/P;y/_./\n\n/;D' > 2_val.txt
head [12]_val.txt
==> 1_val.txt <==
1
2
4
2
4
1
2
==> 2_val.txt <==
1
1
1
2
2
3
3
行的分解:
- 调用 sed 时不带自动打印 (-n) 选项,因为我们对快速打印模式不感兴趣,而只对文件名感兴趣。
- 使用单独的流 (-s) 选项调用 sed。通常 sed 将所有文件视为一个流。
- 假设数据行不能包含 # 字符,我们连接下一行并检查它是否非空。在这种情况下,使用 F 命令打印当前文件名。
- 第二个 sed 打印 _ 和点之间的字符串。