我有一个包含 30000 个 txt 文件的文件夹,每个文件为 50-60kb。我需要将它们合并成 2.5mb txt 文件。并删除正在合并的文件。我的代码需要类似于:for f in *,50; do cat file1,file2...file49 > somefile.txt;done
当然这是伪代码。我需要将文件合并为 50 个文件的包,然后删除用过的文件。有人可以帮帮我吗?
答案1
和zsh
:
files=( ./input-file*(Nn.) )
typeset -Z3 n=1
while
(( $#files > 0 )) &&
cat $files[1,50] > merged-file$n.txt &&
rm -f $files[1,50]
do
files[1,50]=()
((n++))
done
扩展./input-file*(Nn.)
为匹配 的文件./input-file*
,但使用 3 个全局限定符进一步分类:
N
: nullglob:使 glob 扩展为空,而不是在没有匹配项时因错误而中止。当从 glob 设置数组时,您经常需要这个,并且该数组最终为空是可以的:n
:numericglobsort
: 将默认的词法排序更改为数字排序(实际上是两者的组合),例如,排序input-file2
在前面。input-file10
.
: 限制为常规的文件(忽略目录、符号链接、fifos...)
typeset -Z3 n
将$n
变量用零填充到宽度 3,所以我们得到merged-file001.txt
, ... merged-file049.txt
...
然后,只要$files
数组中有元素并且没有错误,我们就会循环,一次连接 50 个批次(以及最后一批剩下的任何元素)。
bash 4.4+ 和 GNU 工具也是如此:
readarray -td '' files < <(
LC_ALL=C find . -maxdepth 1 -name 'input-file*' -type f -print0 |
sort -zV
)
n=0
set -- "${files[@]}"
while
(( $# > 0 )) &&
printf -v padded_n %03d "$n" &&
cat "${@:0:50}" > "merged-file$padded_n.txt" &&
rm -f "${@:0:50}"
do
shift "$(( $# >= 50 ? 50 : $# ))"
((n++))
done
find
zsh 的工作在哪里./input-file*(N.)
,sort -V
数字(版本)排序,我们使用位置参数,并且shift
在循环中使用数组,因为bash
数组非常有限。
答案2
这个脚本是:
- 对于 bash (如标记的),
- 避免查找(在无效字符上失败),
- 确保仅处理纯文件(无目录),
- 用于
sort
按数字排序(好吧,按版本)和 - 连接
k
文件(可变计数) - 去除一一次文件(避免复制不会被删除的文件块)
dir="myDir"
readarray -td $'\0' files < <(
for f in ./"$dir"/in-file*; do
if [[ -f "$f" ]]; then printf '%s\0' "$f"; fi
done |
sort -zV
)
k=50
rm -f ./"$dir"/joined-files*.txt
for i in "${!files[@]}"; do
n=$((i/k+1))
cat "${files[i]}" >> ./"$dir"/joined-files$n.txt &&
rm -f "${files[i]}"
done