폴더의 모든 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 확장을 null로 만듭니다. glob에서 배열을 설정할 때 종종 이것이 필요하며 배열이 비어 있어도 괜찮습니다.
  • n: numericglobsort: 기본 어휘 정렬을 숫자 정렬(실제로는 둘의 조합)로 변경합니다. 즉, input-file2앞쪽 정렬입니다.input-file10
  • .: 제한된정기적인파일(디렉토리, 심볼릭 링크, FIFO 무시...)

typeset -Z3 n$n너비가 3이 될 때까지 변수를 0으로 채워서 다음을 얻습니다 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

관련 정보