디렉터리의 모든 파일에서 생성된 텍스트 파일이 있습니다. 이 파일을 내가 가지고 있는 스크립트에 대한 입력으로 사용하고 싶지만 올바르게 구문 분석하려면 특정 방식으로 형식이 지정된 텍스트 파일이 필요합니다.
현재 텍스트 파일(파일 이름 목록)의 형식은 다음과 같습니다.
A1_R1.fastq.gz
A1_R2.fastq.gz
A2_R1.fastq.gz
A2_R2.fastq.gz
A3_R1.fastq.gz
A3_R2.fastq.gz
RN
각 샘플이 탭으로 구분되어 동일한 줄에 있도록 쌍으로 된 읽기(이름은 같지만 값이 다른 파일)가 필요합니다 .
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
A3_R1.fastq.gz A3_R2.fastq.gz
1000개 이상의 항목이 있으므로 awk 또는 이와 유사한 것을 사용하여 파일을 수정하는 방법을 원하지만 awk에 대한 경험이 많지 않습니다.
답변1
질문에 표시된 대로 줄이 정렬되어 있다고 가정하면 이 paste
명령은 다음을 수행할 수 있습니다.
$ paste - - < input_file
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
A3_R1.fastq.gz A3_R2.fastq.gz
-d
기본 TAB 이외의 항목으로 열을 구분하려면 이 옵션을 사용하세요 paste
. 간단한 공간의 경우:
$ paste -d ' ' - - <input_file
답변2
모든 라인 쌍이 서로 인접한 표시된 입력의 경우 awk에 필요한 것은 다음과 같습니다.
$ awk '{ORS=(NR%2 ? "\t" : RS)} 1' file
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
A3_R1.fastq.gz A3_R2.fastq.gz
또는 아직 페어링되지 않은 경우:
$ shuf file > file1
$ cat file1
A3_R2.fastq.gz
A2_R2.fastq.gz
A1_R1.fastq.gz
A3_R1.fastq.gz
A1_R2.fastq.gz
A2_R1.fastq.gz
따라서 다음에 대한 호출을 추가해도 괜찮다면 다음을 수행하십시오 sort
.
$ awk '{ORS=(NR%2 ? "\t" : RS)} 1' <(sort file1)
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
A3_R1.fastq.gz A3_R2.fastq.gz
아니면 awk로 페어링하세요:
$ awk -F'_' -v OFS='\t' '$1 in a{print a[$1], $0; next} {a[$1]=$0}' file1
A3_R2.fastq.gz A3_R1.fastq.gz
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R2.fastq.gz A2_R1.fastq.gz
마지막 스크립트에서는 경우에 따라 R2 필드가 R1 파트너보다 먼저 출력됩니다. 이것이 문제인 경우 인쇄하면서 주문할 수 있습니다.
$ awk -F'_' -v OFS='\t' '
$1 in a { print (a[$1] < $0 ? a[$1] OFS $0 : $0 OFS a[$1]); next }
{ a[$1] = $0 }
' file1
A3_R1.fastq.gz A3_R2.fastq.gz
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
입력 파일에 실제로 수백만 줄이 있는 경우 delete a[$1];
이전에 추가하면 next
대부분의 경우 실행 시간이 빨라지고, 수천 줄에 불과하다면 그럴 가치가 없을 것입니다( delete a[$1]
각 쌍을 호출하는 오버헤드와 큰 해시를 갖는 오버헤드를 비교해보세요). 표면 a[]
).
출력 라인을 정렬해야 한다면 GNU awk를 사용해야 합니다 PROCINFO["sorted_in"]
:
$ awk '{a[$0]} END{PROCINFO["sorted_in"]="@ind_str_asc"; for (i in a) printf "%s%s", i, (++n % 2 ? "\t" : RS) }' file1
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
A3_R1.fastq.gz A3_R2.fastq.gz
그러나 사용된 솔루션과 마찬가지로 sort
입력의 숫자가 여러 숫자일 수 있는 경우 예상된 순서를 생성하지 않습니다. 예를 들어 A11
이전에는 알파벳순으로 정렬되었기 때문입니다 A2
. 각 문자열을 별도의 알파벳 및 숫자 부분으로 분리해야 합니다. 각 부분을 별도로 정렬하거나 각 위치에 항상 동일한 숫자 알파벳 및 숫자 문자가 있도록 정규화합니다(예: A1_R1
정렬하기 전에 매핑).000A0001_000R0001
답변3
사용행복하다(이전 Perl_6)
항상 쌍으로 읽고 순서가 올바른 경우:
~$ raku -e '.put for lines.rotor(2);' file
항상 쌍으로 읽었지만 파일 이름이 순서가 잘못된 경우:
~$ raku -e '.put for lines.sort.rotor(2);' file
Raku는 Perl 계열의 프로그래밍 언어입니다. @EdMorton의 탁월한 답변과 유사하게 awk
파일 이름을 정렬해야 하는 경우 결과 순서는 알파벳순입니다.
https://docs.raku.org/routine/lines
https://docs.raku.org/routine/rotor
https://raku.org
파일 이름 순서에 상관없이 파일이 누락되는 경우가 있습니다.
~$ raku -ne 'BEGIN my %hash; \
%hash.append: .match(/^ (<-[_]>+) _ /).[0] => $_; \
END for %hash.sort { .values.put };' file
#OR
~$ raku -ne 'BEGIN my %hash; \
%hash.append: m/^ (<-[_]>+) _ /.[0] => $_; \
END for %hash.sort { .values.put };' file
두 번째 방법은 입력 데이터가 원본이 아닌 경우(파일 이름 누락 등)에 적합합니다. Perl 자체와 마찬가지로 Raku에는 ("non-auto-print-line") 플래그를 통해 호출되는 awk
명령줄과 유사한 모드가 있습니다. -ne
위에서는 BEGIN
a를 선언하여 이 작업을 수행합니다 %hash
. 이 "한 줄짜리" 본문에서 각 줄은 .match
ed on입니다(여기에는 줄의 텍스트를 보유하는 테마 변수인 on 함수를 호출하는 약어가 .match
있습니다 ).$_.match
$_
.match
(또는) 루틴 m/ … /
/operator는 ^
줄의 시작, <-[_]>+
밑줄 이외의 하나 이상의 문자 (예: 사용자 지정 부정 문자 클래스), 밑줄 자체를 _
찾습니다 . _
(참고용으로만 맞춤설정하세요.긍정적인캐릭터 클래스는 다음과 같습니다 <+[ … ]>
:). 괄호는 밑줄이 그어지지 않은 선행 텍스트를 $0
다음과 같이 캡처합니다 .[0]
.
.[0]
따라서 각 행은 with key
( $_
전체 행) 으로 해석됩니다 value
. =>
키/값 쌍을 만드는 데 사용됩니다 . 해시 데이터 구조는 고유하게 유지되므로 동일한 값이 나타날 때 keys
마다 새로운 값이 얻어집니다 . 읽기 줄 끝 에서 키를 누른 다음 각 키를 꺼냅니다.key
append
END
sort
put
.values
https://course.raku.org/essentials/associatives/hashes/
https://docs.raku.org/언어/hashmap
https://raku.org
입력 예:
A1_R1.fastq.gz
A1_R2.fastq.gz
A2_R1.fastq.gz
A2_R2.fastq.gz
A3_R1.fastq.gz
A3_R2.fastq.gz
출력 예(두 방법 중 하나):
A1_R1.fastq.gz A1_R2.fastq.gz
A2_R1.fastq.gz A2_R2.fastq.gz
A3_R1.fastq.gz A3_R2.fastq.gz
답변4
나는 그것의 팬입니다 sed
. 인접한 전선 쌍을 쉽게 연결할 수 있습니다.
sed 'N; s/\n/'$'\t''/' < input > output
중간에 있는 것은 $'\t'
단일 탭 문자를 전달하는 bash-ism이며 sed
. 실제로는 리터럴 탭을 사용하겠지만 이 매체에는 이것이 명확하게 반영되지 않습니다.sed 'N; s/\n/ /' < input > output
설명하다:
sed
첫 번째 줄부터 읽으세요.- 다음 입력 줄을 읽고 이를 현재 입력 줄에 추가하고 개행 문자
N
로 구분하도록 지시합니다.sed
- 이
s
명령은 줄 바꿈을 탭으로 바꿉니다. - 더 이상 명령이 없으면 이전 단계의 결과를 쓴 후
sed
다음 줄을 읽고 루프백합니다. sed
입력이 소진되면 종료됩니다.