거의 1,100만 개의 작은 파일이 포함된 디렉토리가 있습니다. 다음과 같습니다.
wa_filtering_DP15_good_pops_snps_file_1
wa_filtering_DP15_good_pops_snps_file_2
.
.
.
wa_filtering_DP15_good_pops_snps_file_11232111
각 파일에는 아래와 같이 2개의 행과 315개의 열만 있습니다.
1 0 0 0 0 0 0 0 0 0 1 2 1
0 0 0 0 0 0 0 0 0 0 0 0 0
각 파일을 반복하고 두 행의 각 열에 0 값이 있으면 이를 9로 바꾸고 다음과 같은 결과를 얻습니다.
1 9 9 9 9 9 9 9 9 9 1 2 1
0 9 9 9 9 9 9 9 9 9 0 0 0
누군가 내가 이 작업을 수행하는 방법을 알아내도록 도와줄 수 있습니까? 감사해요
답변1
awk
해결책 은 다음과 같습니다 .
awk '{split($0,ary1,/[ ]+/); getline x; split(x,ary2,/[ ]+/);
for (i in ary1)if (!(ary1[i]+ary2[i])){ary1[i]=ary2[i]=9}}
END{for (r=1;r<=NF;r++) printf ("%d ", ary1[r]); printf"\n";
for (z=1;z<=NF;z++) printf ("%d ", ary2[z]); printf"\n"}' infile
설명하다:
split($0,ary1,/[ ]+/);
ary1
: 첫 번째 줄을 읽고 배열 사이에 하나 이상의 공백 구분 기호를 사용하여 배열로 분할합니다 .getline x; split(x,ary2,/[ ]+/);
: 두 번째 줄을 변수로 읽어서x
배열로 나눕니다ary2
.for (i in ary1)if (!(ary1[i]+ary2[i])){ary1[i]=ary2[i]=9}}
: 두 필드 값의 합이 다음과 같은 경우 배열의ary1
각 인덱스를 반복합니다.i
영(참 조건에서 트리거됩니다!(0)
.) 그런 다음 두 필드의 값을 다음으로 설정합니다.if(1)
9
for (r=1;r<=NF;r++) printf ("%d ", ary1[r]); printf"\n";
ary1
: 이제 각 배열의 최종 값과 다음 행을 인쇄합니다ary2
.
약 1,100만 개의 파일 전체에 적용하려면 FILENAME.out
현재 읽을 입력 파일 이름을 나타내는 FILENAME 형식 으로 변경 사항을 저장하기만 하면 됩니다 awk
.
awk '{split($0,ary1,/[ ]+/); getline x; split(x,ary2,/[ ]+/);
for (i in ary1)if (!(ary1[i]+ary2[i])){ary1[i]=ary2[i]=9}}
END{for (r=1;r<=NF;r++) printf ("%d ", ary1[r])>FILENAME".out"; printf"\n">FILENAME".out";
for (z=1;z<=NF;z++) printf ("%d ", ary2[z])>FILENAME".out"
}' wa_filtering_DP15_good_pops_snps_file_{1..11232111}
답변2
재미삼아 이건 Ruby
ruby -e '
data = File.readlines(ARGV.shift)
.map {|line| line.split.map(&:to_i)}
.transpose
.map {|(a,b)| (a==0 && b==0) ? [9,9] : [a,b]}
.transpose
.each {|row| puts row.join(" ")}
' file
1 9 9 9 9 9 9 9 9 9 1 2 1
0 9 9 9 9 9 9 9 9 9 0 0 0
모든 파일을 바꾸려면:
ruby -e '
require "tempfile"
require "pathname"
Pathname.new("/path/to/your/files/").each_child do |pathname|
next unless pathname.file?
temp = Tempfile.new(pathname.basename.to_s)
filename = pathname.to_s
File.readlines(filename)
.map {|line| line.split.map(&:to_i)}
.transpose
.map {|(a,b)| (a==0 && b==0) ? [9,9] : [a,b]}
.transpose
.each {|row| temp.puts row.join(" ")}
temp.close
File.link filename, filename+".bak"
File.rename temp.path, filename
end
'
답변3
이는 순수한 awk 솔루션에 비해 수백만 개의 파일에 대해 속도가 느릴 수 있는 대안입니다.
비슷한 접근 방식을 사용하여 행을 열로 바꿀 수 있습니다.
$ cat file1
1 0 0 0 0 0 0 0 0 0 1 2 1
0 0 0 0 0 0 0 0 0 0 0 0 0
$ paste -d'-' <(head -n1 file1 |tr -s ' ' '\n') <(tail -n1 file1 |tr -s ' ' '\n')
1-0
0-0
0-0
0-0
0-0
0-0
0-0
0-0
0-0
0-0
1-0
2-0
1-0
0-0
그런 다음 모든 항목을 간단한 sed로 바꾸고 9-9
출력을 임시 변수에 저장할 수 있습니다.
$ f1=$(sed 's/0-0/9-9/g' <(paste -d'-' <(head -n1 file1|tr -s ' ' '\n') <(tail -n1 file1 |tr -s ' ' '\n')))
$ echo "$f1"
1-0
9-9
9-9
9-9
9-9
9-9
9-9
9-9
9-9
9-9
1-0
2-0
1-0
이제 열에서 행으로 복원할 수 있습니다. 예를 들면 다음과 같습니다.
$ awk -F'-' 'NR==FNR{printf "%s ",$1;p=1;next}p{printf "\n";p=0}{printf "%s ",$2}END{printf "\n"}' <(echo "$f1") <(echo "$f1")
1 9 9 9 9 9 9 9 9 9 1 2 1
0 9 9 9 9 9 9 9 9 9 0 0 0
>file1
마지막 awk 명령 끝에 추가하여 file1
새 내용으로 덮어쓸 수도 있습니다 .
남은 유일한 것은 모든 파일을 반복하는 것입니다. 이는 bash 루프를 통해 수행할 수 있습니다.
for f in ./wa_filtering_DP15_good_pops_snps_file_*;do
f1=$(sed 's/0-0/9-9/g' <(paste -d'-' <(head -n1 "$f"|tr -s ' ' '\n') <(tail -n1 "$f" |tr -s ' ' '\n')))
awk -F'-' 'NR==FNR{printf "%s ",$1;p=1;next}p{printf "\n";p=0}{printf "%s ",$2}END{printf "\n"}' <(echo "$f1") <(echo "$f1") #>"$f" #uncomment >"$f" to overwrite the files...
done
답변4
첫 번째 변형:
단일 파일의 경우:
datamash -W transpose < input.txt | sed 's/0\t0/9\t9/' | datamash transpose
많은 파일에 대해 루프에서 동일한 작업을 수행합니다.
for i in *; do datamash -W transpose < "$i" |
sed 's/0\t0/9\t9/' |
datamash transpose > "new_$i"; done
이 루프는 "new_"라는 접두사가 붙은 각 파일에 대해 변경된 새 파일을 생성합니다. 그런 다음 이전 파일을 모두 삭제하고 파일 이름에서 접두사 "new_"를 제거할 수 있습니다.
두 번째 변형:
이는 단일 파일에 대한 솔루션입니다. 여러 파일의 경우 이전 변형에 표시된 대로 루프를 사용합니다.
tr '\n' '\t' < input.txt |
awk '{
num = NF / 2;
for(up = 1; up <= NF; up++) {
if(up <= num) {
low = num + up;
if(!$up && !$low) {
$up = 9;
$low = 9;
}
}
printf "%s\t", $up;
if(up % num == 0)
print "";
}
}'
설명하다
tr '\n' '\t' < input.txt
- 두 개의 전선을 함께 연결하십시오.awk
- 첫 번째 행의 요소와 두 번째 행의 인접 요소를 모두 확인합니다. 예를 들면 다음과 같습니다.1그리고316,2그리고317화,삼그리고318, 곧.
- 두 요소가 모두 있는 경우0, 그러면 다음과 같이 변경됩니다.9.
- 필드를 순서대로 인쇄 -1, 2, 3, 4 ... 628, 629, 630.
- 요소 수가 행에 있는 요소 수의 배수가 될 때마다 새 행이 추가됩니다.
입력하다
1 0 0 0 0 0 0 0 0 0 1 2 1
0 0 0 0 0 0 0 0 0 0 0 0 0
산출
1 9 9 9 9 9 9 9 9 9 1 2 1
0 9 9 9 9 9 9 9 9 9 0 0 0