合并文件夹中的每第 n 个文件并删除已使用的文件

合并文件夹中的每第 n 个文件并删除已使用的文件

我有一个包含 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

findzsh 的工作在哪里./input-file*(N.)sort -V数字(版本)排序,我们使用位置参数,并且shift在循环中使用数组,因为bash数组非常有限。

答案2

这个脚本是:

  1. 对于 bash (如标记的),
  2. 避免查找(在无效字符上失败),
  3. 确保仅处理纯文件(无目录),
  4. 用于sort按数字排序(好吧,按版本)和
  5. 连接k文件(可变计数)
  6. 去除一次文件(避免复制不会被删除的文件块)
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

相关内容