많은 수의 파일 병합

많은 수의 파일 병합

res.1±10,000개의 파일( - ) 이 있는데 res.10000모두 하나의 열과 동일한 수의 행으로 구성되어 있습니다. 내가 원하는 것은 본질적으로 간단합니다. 모든 파일을 열 단위로 새 파일로 병합합니다 final.res. 나는 다음을 사용해 보았습니다.

paste res.*

그러나 (이것은 결과 파일의 작은 하위 집합에 대해 작동하는 것처럼 보이지만 전체 컬렉션에서 실행하면 다음 오류가 발생합니다. Too many open files.

이를 달성하는 "쉬운" 방법이 있어야 합니다. 그러나 불행하게도 저는 유닉스를 처음 접하는 사람입니다. 미리 감사드립니다!

추신: (내) 데이터 파일 중 하나가 어떻게 생겼는지에 대한 아이디어를 제공하려면 다음을 수행하십시오.

0.5
0.5
0.03825
0.5
10211.0457
10227.8469
-5102.5228
0.0742
3.0944
...

답변1

머신에 대한 루트 액세스 권한이 있는 경우 최대 열린 파일 설명자 수 제한을 일시적으로 늘릴 수 있습니다.

ulimit -Hn 10240 # The hard limit
ulimit -Sn 10240 # The soft limit

그런 다음

paste res.* >final.res

나중에 원래 값으로 다시 설정할 수 있습니다.


두 번째 해결책, 한도를 변경할 수 없는 경우:

for f in res.*; do cat final.res | paste - $f >temp; cp temp final.res; done; rm temp

파일당 한 번씩 호출 되며 paste모든 열이 포함된 거대한 파일이 생성됩니다(1분 정도 소요).

편집하다:고양이에게 쓸모없는 용도...아니요!

댓글에서 언급했듯이 cat여기서 ()를 사용하는 것은 cat final.res | paste - $f >temp쓸모가 없습니다. 루프를 처음 실행하면 파일이 final.res아직 존재하지 않습니다. paste그런 다음 실패하고 파일이 채워지지 않고 생성되지 않습니다. 내 솔루션은 cat처음에만 실패 No such file or directory하고 paste표준 입력에서 빈 파일을 읽지만 계속됩니다. 이 오류는 무시할 수 있습니다.

답변2

만약에착란' 답변이 적용되지 않는 경우(필수 권한이 ​​없기 때문에) paste다음과 같이 일괄 호출할 수 있습니다.

ls -1 res.* | split -l 1000 -d - lists
for list in lists*; do paste $(cat $list) > merge${list##lists}; done
paste merge* > final.res

이번에는 etc라는 파일에 있는 1000개의 파일이 나열된 lists00다음 lists01해당 res.파일을 etc라는 파일에 붙여넣고 마지막 merge00으로 merge01부분적으로 병합된 결과 파일이 모두 병합됩니다.

말한 바와 같이착란한 번에 사용하는 파일 수를 늘릴 수 있습니다. 제한은 주어진 값에서 ulimit -n열려 있는 파일 수를 뺀 값입니다.

ls -1 res.* | split -l $(($(ulimit -n)-10)) -d - lists

사용 한도에서 10포인트 할인됩니다.

귀하의 버전이 split이를 지원하지 않는 경우 -d제거할 수 있습니다. split숫자 접미사를 사용하라는 메시지만 표시됩니다. 기본적으로 접미사는 aaab대신 등이 됩니다 01.02

파일이 너무 많아 실패하는 경우 ls -1 res.*("매개변수 목록이 너무 김") 다음으로 바꿀 수 있습니다 find.

find . -maxdepth 1 -type f -name res.\* | split -l 1000 -d - lists

(지시했듯이돈 크리스티, 출력을 파이핑할 때는 필요하지 않지만 -1별칭 의 경우를 ls처리하기 위해 그대로 둡니다 . )ls-C

답변3

다음과 같이 실행해 보세요.

ls res.*|xargs paste >final.res

배치를 여러 부분으로 분할하고 다음을 시도해 볼 수도 있습니다.

paste `echo res.{1..100}` >final.100
paste `echo res.{101..200}` >final.200
...

마지막으로 최종 파일을 병합합니다.

paste final.* >final.res

답변4

관련된 파일 수, 줄 크기 등을 고려할 때 도구의 기본 크기(awk, sed, 붙여넣기, * 등)를 초과할 것이라고 생각합니다.

이를 위해 10,000개의 파일이나 수십만 줄(각각 10줄이 있는 10,000개의 파일(예제에서는 줄의 최대 크기))을 열지 않는 작은 프로그램을 만들겠습니다. 각 파일에서 읽은 바이트 수를 저장하려면 약 10,000개의 정수 배열만 필요합니다. 단점은 파일 설명자 하나만 있고 파일당, 줄당 재사용되므로 속도가 느려질 수 있다는 것입니다.

FILES및 의 정의는 ROWS실제 정확한 값으로 변경되어야 합니다. 출력은 표준 출력으로 전송됩니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILES 10000 /* number of files */
#define ROWS 500    /* number of rows  */

int main() {
   int positions[FILES + 1];
   FILE *file;
   int r, f;
   char filename[100];
   size_t linesize = 100;
   char *line = (char *) malloc(linesize * sizeof(char));

   for (f = 1; f <= FILES; positions[f++] = 0); /* sets the initial positions to zero */

   for (r = 1; r <= ROWS; ++r) {
      for (f = 1; f <= FILES; ++f) {
         sprintf(filename, "res.%d", f);                  /* creates the name of the current file */
         file = fopen(filename, "r");                     /* opens the current file */
         fseek(file, positions[f], SEEK_SET);             /* set position from the saved one */
         positions[f] += getline(&line, &linesize, file); /* reads line and saves the new position */
         line[strlen(line) - 1] = 0;                      /* removes the newline */
         printf("%s ", line);                             /* prints in the standard ouput, and a single space */
         fclose(file);                                    /* closes the current file */
      }
      printf("\n");  /* after getting the line from each file, prints a new line to standard output */
   }
}

관련 정보