A_bla.csv
(예: 등...) 과 같은 여러 파일이 있습니다 B_bla.csv
C_bla.csv
(이것은 실제 파일의 정렬 하위 샘플이지만 열 수는 실제입니다).
1,test,test2,55.2,test3
1,test,test2,96.3,test3
1,test,test2,64.2,test3
1,test,test2,97.2,test3
및 기본 파일 main.tsv
(필드 구분 기호 = \t
):
id coverage clade
A wrongdata 20
B wrongdata 19
C wrongdata 19
*_bla.csv
coverage
각 파일의 4열, 89행의 필드를 파일 열에 인쇄하고 싶습니다 main.tsv
. 이렇게 하려면 *_bla.csv
파일의 FILENAME을 사용하고 이를 id
파일 열의 패턴 으로 사용해야 합니다 main.tsv
.
지금까지 나는 다음을 시도했습니다.
for file in *_bla.csv ; do
r="$(basename -s "_bla.csv" $file)"
awk ... ;
done
하지만 이제 곧 답변을 시작하겠습니다. Linux 시스템에 기본으로 제공되는 도구(awk, grep, sed, python, perl...)만 사용하여 이를 수행하는 방법을 알고 계십니까? 감사해요
답변1
피할 수 없는 GNU sed
라인:
sed '1n;h;s/\([[:alnum:]]\).*/sed -E "89!d;s_([^,]*,){3}__;s_,.*__" \1_bla.csv/e;G;s/\(.*\)\n\(.*\)wrongdata/\2\1/' main.tsv
마법은 무엇입니까? e
대체 명령의 xecute 옵션을 사용 하고 다른 명령을 사용하여 s
89행의 4번째 필드를 추출합니다. sed
상세히:
1n
첫 번째 줄은 변경하지 않고 그대로 둡니다.h
엉망이 되기 전에 예약된 공간에 라인을 저장하세요\([[:alnum:]]\).*
전체 줄을 일치시키고 교체 시\(\)
참조 할 수 있도록 첫 번째 영숫자 필드를 캡처합니다.\1
sed -E "89!d;s_([^,]*,){3}__;s_,.*__" \1_bla.csv
대체 방법은 다음과 같습니다. 89를 제외한 모든 행이 삭제되고d
처음 세 필드가 삭제되며 마지막으로 새로운 첫 번째 필드 이후의 모든 항목이 삭제됩니다. 따라서 실제로는 89행의 네 번째 필드만 남아 있으므로e
버퍼 실행에 의해 이 필드가 반환됩니다.- 이제 저장 공간에 저장 라인을 추가
G
하고 추출된 필드로 바꾸면 됩니다s/\(.*\)\n\(.*\)wrongdata/\2\1/
.wrongdata
답변2
awk -F',|\t' '
FILENAME != "main.tsv" && FNR == 89 {
sub(/_.*$/, "", FILENAME)
A[FILENAME]=$4
}
FILENAME != "main.tsv" {next}
A[$1] {$2 = A[$1]}
{print}
' *bla.csv OFS='\t' main.tsv
파일에 탭 구분 기호가 없습니다 main.tsv
. 그런 다음 패턴을 다음과 같이 수정해야 합니다.-F',|[[:blank:]]+'
답변3
awk 유틸리티를 사용하여 이 작업을 수행할 수 있습니다. csv 파일이 있는 디렉터리에서 실행해야 합니다.
awk -v OFS='\t' '
FS=="," && FNR==89 {
split(FILENAME, a, "_")
h[substr(a[1],3)] = $4
}
f=FS=="\t" {
$2 = FNR>1&&($1 in h) ? h[$1] : $2
};f
' FS=, ./*_bla.csv FS="\t" ./main.tsv
id coverage clade
A 35.8 20
B 65.7 19
C 35.8 19
perl -F, -lane '
if (@ARGV) {
89..89 && do{
$h{($ARGV=~/^..(\w+)_/)[0]} = $F[3];
close ARGV;
};
} else { #last file here
@F = split "(\t)";
$F[2] = $h{$F[0]} // $F[2];
print($.>1?@F:$_)
}
' ./*_bla.csv ./main.tsv
GNU sed. 하지만 먼저 각 CSV 파일에서 89행, 필드 4를 파악하고 sed s/// 문의 RHS를 안전하게 삽입할 수 있도록 나타나는 데이터를 이스케이프합니다.
hold=$(
grep -Pzo '^(?:.*\n){88}(?:[^,]*,){3}\K[^,]*' -- *_bla.csv |
tr '\0' '\n'|
sed -Ee '
s/_.*:/\t/
s:[\&/]:\\&:g
$!s:$:\\:
')
sed -En \
-e "1{x;s/.*/$hold/;x;}" \
-e '
1!G
s/^(\S+\t)wrongdata(\t.*)\n\1([^\n]*)/\1\3\2/
P
' \
./main.tsv
python3 -c '
import sys, pathlib, itertools
mainf = sys.argv[1]
fs,rs = ofs,ors = "\t","\n"
d,dlm = {},","
for p in pathlib.Path(".").glob("*_bla.csv"):
if p.is_file():
id = p.name[:p.name.find("_")]
with open(p.name) as f:
d[id] = [l.rstrip(rs).split(dlm)[3] for l in itertools.islice(f,88,89)][0]
with open(mainf) as f:
for l in f:
L = l.rstrip(rs).split(fs)
print(L[0], d.get(L[0],L[1]), *L[2:], sep=ofs)
' ./main.tsv