![Bash:循环多个文件并打印每个文件的每一行并写入不同的文件](https://linux22.com/image/195137/Bash%EF%BC%9A%E5%BE%AA%E7%8E%AF%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6%E5%B9%B6%E6%89%93%E5%8D%B0%E6%AF%8F%E4%B8%AA%E6%96%87%E4%BB%B6%E7%9A%84%E6%AF%8F%E4%B8%80%E8%A1%8C%E5%B9%B6%E5%86%99%E5%85%A5%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%87%E4%BB%B6.png)
我有 3 个文件,行数不同。我试图循环遍历这三个文件,并将每个文件的第一行打印到新文件 output1.txt 中,然后将每个文件的第二行打印到另一个新文件 output2.txt 中,依此类推。由于每个文件的行数不同,如果几行没有 file2 和 file3 的条目,则它应该忽略并在创建的后续输出文件中不打印任何内容。我怎样才能在 bash 中实现这一目标?
文件1
xyz
abc
def
ghi
jkl
文件2
123
456
789
文件3
ax1
by2
输出文件
输出1.txt
xyz
123
ax1
输出2.txt
abc
456
by2
输出3.txt
def
789
输出4.txt
ghi
输出5.txt
jkl
答案1
使用bash
告诉awk
去做这件事,这就是 bash 的用途(而不是,例如,本身进行文本处理)。
例如,以下 awk 单行语句将每个输入行写入由文字字符串“output”、当前输入文件的当前行号(awk 变量FNR
)和文字字符串“.txt”构造的文件名:
$ awk '{print > "output" FNR ".txt"}' file*
$ tail output*
==> output1.txt <==
xyz
123
ax1
==> output2.txt <==
abc
456
by2
==> output3.txt <==
def
789
==> output4.txt <==
ghi
==> output5.txt <==
jkl
注意:如果您有大量输出文件(数百个或更多),您可能会遇到问题。对于某些版本的 awk,如果超出了内核和登录环境允许进程的文件句柄数,则进程可能会因错误而终止。对于其他版本的 awk(例如 GNU awk),它在管理在任何给定时刻打开哪些文件句柄进行写入时可能会减慢速度。除非您的某些输入文件长达数百行,否则这不太可能成为问题。
以下内容适用于任何版本的 awk 以及任何长度的输入文件(因为它一次只打开一个输出文件进行写入),但速度会慢得多因为它会为每次写入打开输出文件,并在写入后立即关闭它。即便如此,它仍然比在 shell 中执行此操作快许多倍。
awk '{
# use 5-digit zero-padded output filenames for this version
# e.g. output00001.txt
out = sprintf("output%05i.txt", FNR);
if (out in files) {
# we have written to this file before, so append to it
print >> out
} else {
# first write to this file, so create or truncate it.
print > out
files[out]=1
}
close(out)
}' file*
答案2
我的同事建议的以下解决方案对我有用。感谢大家抽出时间回答我的问题。对此,我真的非常感激。
# for flattening and merging the file and writing to a tempfile
pr -J -m -t file* --sep-string=';' > mergedfile
# Now you have data in each line which can be looped and redirected to respective filenames based on the loop count
# No.of files will be equal to the biggest file in the input, in this case , you will see 240 files
i=1
while read line; do
echo "=======file no: $i ========"
echo $line|sed -e 's@^;@@g' -e 's@;;@@g'|tr ';' '\n' > output${i}.txt
let i=i+1
done < mergedfile