如何根据需要将所有文件合并为一个文件
Posted
技术标签:
【中文标题】如何根据需要将所有文件合并为一个文件【英文标题】:How to combine all files into one file, as I want 【发布时间】:2021-01-04 18:17:09 【问题描述】:一个文件夹中有 1000 个 txt 文件。 文件内容如下:
("a1", "b1")
我想将所有文件合并为一个文件。但是,我必须用逗号分隔每个文件的内容。
("a1", "b1"), ("a2", "b2")
然后我需要在开头和结尾添加一个固定的文本,如下所示。
START ("a1", "b1"), ("a2", "b2") END
但是,只要要添加的文件数为100,就应该创建一个新行。
例子:
START ("a1", "b1"), ("a2", "b2") ... END
...
START ("a900", "b900"), ("a901", "b901") ... END
我在示例中给出的值只是示例,以更简单的方式解释。
我需要将其编写为 bash 脚本以在服务器上运行。
我能够执行以下操作,但我认为这不是好的代码。 不幸的是,我无法在每 100 个文件中创建一个新行。
echo "START " > all.txt
cat *.txt >> all.txt
sed -i 's/)(/),(/g' all.txt
echo " END" >> all.txt
坦率地说,我需要你的帮助,因为这对我来说是一个非常复杂的代码。
我愿意接受您的宝贵意见和建议。
谢谢。
【问题讨论】:
【参考方案1】:这里尝试使用 awk 单行(我使用 3 列以便于演示):
awk 'BEGINprintf "START " NR == 1 printf "%s", $0; next NR % 3 == 1 printf " END\nSTART %s", $0;next printf ", %s", $0 END print " END"' file*
$ awk 'BEGINprintf "START " NR == 1 printf "%s", $0; next NR % 3 == 1 printf " END\nSTART %s", $0;next printf ", %s", $0 END print " END"' file*
START (10, 0), (11, 0), (12, 0) END
START (13, 0), (14, 0), (15, 0) END
START (16, 0), (17, 0), (18, 0) END
START (19, 0), (20, 0), (21, 0) END
START (22, 0), (23, 0), (24, 0) END
START (25, 0), (26, 0), (27, 0) END
START (28, 0), (29, 0), (30, 0) END
START (31, 0), (32, 0), (33, 0) END
START (34, 0), (35, 0), (36, 0) END
START (37, 0), (38, 0), (39, 0) END
START (40, 0), (41, 0), (42, 0) END
START (43, 0), (44, 0), (45, 0) END
START (46, 0), (47, 0), (48, 0) END
START (49, 0), (50, 0), (51, 0) END
START (52, 0), (53, 0), (54, 0) END
START (55, 0), (56, 0), (57, 0) END
START (58, 0), (59, 0), (60, 0) END
START (61, 0), (62, 0), (63, 0) END
START (64, 0), (65, 0), (66, 0) END
START (67, 0), (68, 0), (69, 0) END
START (70, 0), (71, 0), (72, 0) END
START (73, 0), (74, 0), (75, 0) END
START (76, 0), (77, 0), (78, 0) END
START (79, 0), (80, 0), (81, 0) END
START (82, 0), (83, 0), (84, 0) END
START (85, 0), (86, 0), (87, 0) END
START (88, 0), (89, 0), (90, 0) END
START (91, 0), (92, 0), (93, 0) END
START (94, 0), (95, 0), (96, 0) END
START (97, 0), (98, 0), (99, 0) END
或者以更易读的格式:
BEGIN printf "START "
NR == 1 printf "%s", $0; next
NR % 3 == 1 printf " END\nSTART %s", $0; next
printf ", %s", $0
END print " END"
如果您确实有大量文件,您可能会收到argument list too long
错误。要解决此问题,请改用 xargs
。
echo file* | xargs awk '......' > joined
这看起来会有同样的问题,但是因为echo
是内置于bash
,所以它不受参数长度限制的约束。
【讨论】:
代码运行良好,只有一个错误。文件 2 被读取两次。开始 2、2、1 结束 开始 3、4、5 结束 开始 6、7 结束 @user14296498:对,最后的检查应该是NR > 1
,更新了答案
1k 文件没有问题。但是当我尝试 100 万个文件时,它会给出这个错误。 awk: 参数列表太长我们能找到解决这个问题的方法吗?
@user14296498:这可以用xargs
修复,请参阅答案中的编辑。【参考方案2】:
应该这样做(未经测试):
awk '
rec = (rec=="" ? "" : rec ", ") $0
(NR%100) == 0
print "START", rec, "END"
rec = ""
' *
【讨论】:
我试过你的例子,它奏效了。你的代码更干净,谢谢。我想我会用这个更新它。 我发现了一个错误。如果文件数小于 100 则不起作用。 @user14296498 这不是一个错误。在您的问题中,您说您想要as long as the number of files to be added is 100, it should create a new line.
,这就是脚本的设计目的。您没有说要处理少于 100 或总数不是 100 的倍数。如果您需要处理任何类似的情况,请更新您的问题以至少说明您的要求,因为有几个不同的选项在这种情况下该怎么做(打印子集,不要从前面打印,或者不要从后面打印)。
@user14296498:它可以很容易地修复,只需在最后一行的单括号前添加END print "START", rec, "END"
。或END if (NR%100 != 0) print "START", rec, "END"
【参考方案3】:
我知道你在 shell 中要求它 - 但从技术上讲,如果你在 Python 解决方案前加上 python -c "
,它就是 shell,不是吗? [眨眼]
#! /usr/bin/env python3
import os
contents = []
with ('all.txt', 'wt') as output:
for filename in os.listdir('.'):
if filename == 'all.txt': continue
contents.append(open(filename).read().strip())
if len(contents) >= 100:
output.write(f'''START ', '.join(contents) END\n''')
contents = []
output.write(f'''START ', '.join(contents) END\n''')
【讨论】:
【参考方案4】:Bash 变体
n=1; while read -r line; do
((n==1)) && printf 'start '
printf "$line"
((n>=10)) && printf ' end\n'; n=1 ; \
|| printf ', ' ; ((n++));
done < <(cat file*)
【讨论】:
以上是关于如何根据需要将所有文件合并为一个文件的主要内容,如果未能解决你的问题,请参考以下文章