서로 다른 디렉터리에 있는 여러 파일을 연결합니다.

서로 다른 디렉터리에 있는 여러 파일을 연결합니다.

다른 디렉토리의 여러 파일을 연결하고 싶습니다.

디렉터리 1: Chr1이 예에서는 4개의 파일을 포함합니다.

ABC.1 
DEF.1
GHI.1 
JKL.1 

카탈로그 2:Chr2

ABC.2  
DEF.2 
GHI.2
JKL.2 

22개의 디렉토리가 있습니다. 각 파일에는 20개의 열과 헤더가 있습니다. 헤더는 모든 파일에 동일합니다.

모든 것을 하나의 파일(모든 디렉터리의 모든 파일을 연결하는 전역 출력 파일)로 연결하고 싶습니다.

나는 이것을 시도했지만 작동하지 않습니다.

cat */Chr{1..22}/*.{1..22} > */final_file

파일이 없기 때문에 "해당 파일이나 디렉터리가 없습니다"라고 표시됩니다. 예를 들어 *.1~21은 chr22 디렉터리에 있는 파일입니다.

어떤 생각이 있나요? 미리 감사드립니다.

답변1

그냥 zsh쉘을 사용하세요:

cat -- */Chr<1-22>/*.<1-22>(n) > final_file

에서는 10진수 범위와 일치하는 glob 연산자이며 glob 한정자는 glob 확장이 숫자로 정렬되도록 하는 옵션을 전환 zsh합니다 .<x-y>nnumericglobsort

다른 셸에서는 다음을 수행할 수 있습니다.

zsh -c 'cat -- */Chr<1-22>/*.<1-22>(n) > final_file'

첫 번째 파일을 제외한 모든 헤더를 건너뛰고 GNU 또는 비지박스 구현 tail(Linux를 커널로 사용하는 시스템에서 가장 일반적임)을 가정하려면 다음을 수행할 수 있습니다.

(){
  cat < $1; shift; (($#)) && tail -qn +2 -- "$@"
} */Chr<1-22>/*.<1-22>(n) > final_file 

답변2

접근 방식의 문제점은 반복되는 와일드카드가 "동기적으로"(="확장") 해석되지 않고 명령줄에서 발생할 때마다 다시 해석되고 독립적이라는 것입니다. 따라서 작동하려면 중첩된 셸 루프를 사용해야 합니다.

다음 쉘 스크립트를 시도해 볼 수 있습니다. 기능을 사용한다는 점에 유의하십시오 bash(귀하의 질문은 사용 중인 쉘을 다루지 않습니다)

#!/bin/bash

hdr=0   # initialize variable to keep track of whether the header is already printed

# loop over directories
for d in Chr*
do
    # extract trailing number from dir name by removing 'Chr' part (bash feature!)
    n="${d#Chr}"

    # loop over all files
    for f in "$d/"*".$n"
    do
       if (( hdr == 0 )) # if header wasn't printed yet, output entire file
       then
           cat "$f" > final_file
           hdr=1
       else              # otherwise, output file content starting with line 2
           tail -n +2 "$f" >> final_file
       fi
    done
done

스크립트 이름을 concatenate.sh실행 파일로 지정하고 모든 하위 디렉터리가 있는 디렉터리에서 실행할 수 있습니다 Chr{1..22}. final_file이 디렉토리에도 생성 됩니다 .

너무 멀리 테스트할 수는 없지만 아무 것도 깨져서는 안 됩니다...

답변3

모든 하위 디렉터리의 모든 파일을 캡처하려면 Chr.*다음을 사용할 수 있습니다.

cat Chr*/* >final_file

해당 디렉토리 이름의 접미사와 일치하도록 각 하위 디렉토리의 파일 세트를 제한해야 하는 경우(따라서 Chr1일치하는 파일만 고려 *.1) 루프가 필요합니다.

shopt nullglob    # This is bash-specific
for i in {1..22}
do
    cat Chr$i/*.$i
done >final_file

이 옵션은 shopt nullglob일치할 수 없는 와일드카드 문자를 리터럴 별표로 남겨 두는 대신 와일드카드 문자를 제거하도록 쉘에 지시합니다.

대안으로, 연결된 파일에서 첫 번째 헤더 행을 제외한 모든 것을 생략하려는 것처럼 보이므로 이 확장 루프가 이를 처리할 수 있습니다.

first=yes
for i in {1..22}
do
    for f in Chr$i/*.$i
    do
        [[ -n "$first" ]] && head -n1 "$f" && first=
        cat "$f"
    done
done >final_file

또는 헤더 행이 첫 번째 파일의 첫 번째 행으로 존재하고 이후에 발견되는 모든 곳에서 제거할 수 있는 경우 다음과 같은 구조를 사용하여 제거할 수 있습니다.

for i in {1..22}
do
    cat Chr$i/*.$i
done |
    awk '$0 != header { print } header == "" { header = $0 }' >final_file

관련 정보