在多个输入文件上使用 awk
Using awk on multiple input files
我一直在研究一个 bash
脚本,在这个脚本中的某些时候,我一直在尝试弄清楚如何使用 awk
同时处理两个 CSV 文件,这将用于生成多个输出文件。很快,有一个主文件保存要分派到其他一些输出文件的内容,这些输出文件的名称和需要保留的记录数将从另一个文件派生。第一个 n
记录将转到第一个输出文件,随后的 n+1
到 n+k
到第二个,依此类推。
为了更清楚,这里有一个主记录文件的示例:
x11,x21
x12,x22
x13,x23
x14,x24
x15,x25
x16,x26
x17,x27
x18,x28
x19,x29
以及其他文件的外观:
out_file_name_1,2
out_file_name_2,3
out_file_name_3,4
那么第一个名为 out_file_name_1
的输出文件应该如下所示:
x11,x21
x12,x22
那么名为 out_file_name_2
的第二个输出文件应该如下所示:
x13,x23
x14,x24
x15,x25
最后一个应该是这样的:
x16,x26
x17,x27
x18,x28
x19,x29
希望已经够清楚了。
这是 awk 中的一个解决方案,但显然 triplee 的答案是更好的方法。
$ cat oak.awk
BEGIN { FS = ","; fidx = 1 }
# Processing files.txt, init parallel arrays with filename and number of records
# to print to each one.
NR == FNR {
file[NR] =
records[NR] =
next
}
# Processing main.txt. Print record to current file. Decrement number of records to print,
# advancing to the next file when number of records to print reaches 0
fidx in file && records[fidx] > 0 {
print > file[fidx]
if (! --records[fidx]) ++fidx
next
}
# If we get here, either we ran out of files before reading all the records
# or a file was specified to contain zero records
{ print "Error: Insufficient number of files or file with non-positive number of records"
exit 1 }
$ cat files.txt
out_file_name_1,2
out_file_name_2,3
out_file_name_3,4
$ cat main.txt
x11,x21
x12,x22
x13,x23
x14,x24
x15,x25
x16,x26
x17,x27
x18,x28
x19,x29
$ awk -f oak.awk files.txt main.txt
$ cat out_file_name_1
x11,x21
x12,x22
$ cat out_file_name_2
x13,x23
x14,x24
x15,x25
$ cat out_file_name_3
x16,x26
x17,x27
x18,x28
x19,x29
我不会为此使用 Awk。
while IFS=, read -u 3 filename lines; do
head -n "$lines" >"$filename"
done 3<other.csv <main.csv
从特定文件描述符读取的 read -u
不是完全可移植的,我相信,但是你的问题被标记为 bash 所以我假设这不是问题。
如果您在第一个文件之后得到的是空文件,也许可以尝试用额外的 read
语句替换内部循环。
while IFS=, read -u 3 filename lines; do
for i in $(seq 1 "$lines"); do
read -r line
echo "$line"
done >"$filename"
done 3<other.csv <main.csv
我一直在研究一个 bash
脚本,在这个脚本中的某些时候,我一直在尝试弄清楚如何使用 awk
同时处理两个 CSV 文件,这将用于生成多个输出文件。很快,有一个主文件保存要分派到其他一些输出文件的内容,这些输出文件的名称和需要保留的记录数将从另一个文件派生。第一个 n
记录将转到第一个输出文件,随后的 n+1
到 n+k
到第二个,依此类推。
为了更清楚,这里有一个主记录文件的示例:
x11,x21
x12,x22
x13,x23
x14,x24
x15,x25
x16,x26
x17,x27
x18,x28
x19,x29
以及其他文件的外观:
out_file_name_1,2
out_file_name_2,3
out_file_name_3,4
那么第一个名为 out_file_name_1
的输出文件应该如下所示:
x11,x21
x12,x22
那么名为 out_file_name_2
的第二个输出文件应该如下所示:
x13,x23
x14,x24
x15,x25
最后一个应该是这样的:
x16,x26
x17,x27
x18,x28
x19,x29
希望已经够清楚了。
这是 awk 中的一个解决方案,但显然 triplee 的答案是更好的方法。
$ cat oak.awk
BEGIN { FS = ","; fidx = 1 }
# Processing files.txt, init parallel arrays with filename and number of records
# to print to each one.
NR == FNR {
file[NR] =
records[NR] =
next
}
# Processing main.txt. Print record to current file. Decrement number of records to print,
# advancing to the next file when number of records to print reaches 0
fidx in file && records[fidx] > 0 {
print > file[fidx]
if (! --records[fidx]) ++fidx
next
}
# If we get here, either we ran out of files before reading all the records
# or a file was specified to contain zero records
{ print "Error: Insufficient number of files or file with non-positive number of records"
exit 1 }
$ cat files.txt
out_file_name_1,2
out_file_name_2,3
out_file_name_3,4
$ cat main.txt
x11,x21
x12,x22
x13,x23
x14,x24
x15,x25
x16,x26
x17,x27
x18,x28
x19,x29
$ awk -f oak.awk files.txt main.txt
$ cat out_file_name_1
x11,x21
x12,x22
$ cat out_file_name_2
x13,x23
x14,x24
x15,x25
$ cat out_file_name_3
x16,x26
x17,x27
x18,x28
x19,x29
我不会为此使用 Awk。
while IFS=, read -u 3 filename lines; do
head -n "$lines" >"$filename"
done 3<other.csv <main.csv
从特定文件描述符读取的 read -u
不是完全可移植的,我相信,但是你的问题被标记为 bash 所以我假设这不是问题。
如果您在第一个文件之后得到的是空文件,也许可以尝试用额外的 read
语句替换内部循环。
while IFS=, read -u 3 filename lines; do
for i in $(seq 1 "$lines"); do
read -r line
echo "$line"
done >"$filename"
done 3<other.csv <main.csv