다음 파일이 있습니다.
id name age
1 ed 50
2 joe 70
id
과 age
열만 인쇄하고 싶습니다 . 지금은 그냥 사용합니다 awk
:
cat file.tsv | awk '{ print $1, $3 }'
그러나 열 번호를 알아야합니다. 열 번호 대신 열 이름 (첫 번째 행에 지정)을 사용할 수있는 방법이 있습니까?
id
대신에 $1
하고 age
대신$3
다음 파일이 있습니다.
id name age
1 ed 50
2 joe 70
id
과 age
열만 인쇄하고 싶습니다 . 지금은 그냥 사용합니다 awk
:
cat file.tsv | awk '{ print $1, $3 }'
그러나 열 번호를 알아야합니다. 열 번호 대신 열 이름 (첫 번째 행에 지정)을 사용할 수있는 방법이 있습니까?
id
대신에 $1
하고 age
대신$3
답변:
아마도 이런 식으로 뭔가 :
$ cat t.awk
NR==1 {
for (i=1; i<=NF; i++) {
ix[$i] = i
}
}
NR>1 {
print $ix[c1], $ix[c2]
}
$ awk -f t.awk c1=id c2=name input
1 ed
2 joe
$ awk -f t.awk c1=age c2=name input
50 ed
70 joe
명령 행에 인쇄 할 열을 지정하려면 다음과 같이하십시오.
$ cat t.awk
BEGIN {
split(cols,out,",")
}
NR==1 {
for (i=1; i<=NF; i++)
ix[$i] = i
}
NR>1 {
for (i in out)
printf "%s%s", $ix[out[i]], OFS
print ""
}
$ awk -f t.awk -v cols=name,age,id,name,id input
ed 1 ed 50 1
joe 2 joe 70 2
( 블록에 -v
정의 된 변수를 가져 오려면 스위치를 참고하십시오 BEGIN
.)
awk -f t.awk col1 col2 ... coln input
이상적 일 것입니다. awk -f t.awk cols=col1,col2,...,coln input
너무 일 것이다
for (i in out)
고유 한 순서가 없습니다. 솔루션으로 gawk
제공 PROCINFO["sorted_in"]
하여 인덱스를 반복하는 for( ; ; )
것이 더 좋습니다.
Perl 솔루션을 로트에 넣는 것만으로도 충분합니다.
#!/usr/bin/perl -wnla
BEGIN {
@f = ('id', 'age'); # field names to print
print "@f"; # print field names
}
if ($. == 1) { # if line number 1
@n = @F; # get all field names
} else { # or else
@v{@n} = @F; # map field names to values
print "@v{@f}"; # print values based on names
}
csvkit
입력 데이터를 CSV 형식으로 변환하고 다음과 같은 CSV 도구를 사용 csvcut
하십시오 csvkit
.
$ cat test-cols.dat
id name age
1 ed 50
2 joe 70
csvkit을 설치하십시오.
$ pip install csvkit
tr
squeeze 옵션과 함께 사용 -s
하여 유효한 csv 파일로 변환하고 적용하십시오 csvcut
.
$ cat test-cols.dat | tr -s ' ' ',' | csvcut -c id,age
id,age
1,50
2,70
이전 데이터 형식으로 돌아가려면 다음을 사용할 수 있습니다. tr ',' ' ' | column -t
$ cat test-cols.dat | tr -s ' ' ',' | csvcut -c id,age | tr ',' ' ' | column -t
id age
1 50
2 70
노트
csvkit은 다른 구분 기호 ( 공유 옵션 -d
또는 --delimiter
) 도 지원 하지만 csv 파일을 반환합니다.
파일이 공백을 사용하여 열을 분리하면 (탭이 전혀 없음) 다음 작업이 수행됩니다.
$ csvcut -d ' ' -S -c 'id,age' test-cols.dat
id,age
1,50
2,70
파일이 탭을 사용하여 열을 분리하면 다음 작업이 수행되고 csvformat
tsv 파일을 다시 얻는 데 사용할 수 있습니다.
$ csvcut -t -c 'id,age' test-cols.dat | csvformat -T
id age
1 50
2 70
내가 확인한 한 단일 탭만 허용됩니다.
csvlook
마크 다운 테이블 형식으로 테이블을 형식화 할 수 있습니다.
$ csvcut -t -c "id,age" test-cols.dat | csvlook
| id | age |
| -- | --- |
| 1 | 50 |
| 2 | 70 |
UUOC (Unless Use of Cat) : 명령을 구성하는 것이 좋습니다.
tr
도 있습니다. TSV 파일은 CSV로 변환 할 필요없이 직접 지원됩니다. -t
(일명 --tabs
) 옵션을 알려줍니다 cvscut
필드 구분 기호로 탭을 사용 할 수 있습니다. 그리고 -d
또는 --delimiter
구분 기호로 모든 문자를 사용할 수 있습니다.
-d
및 -t
옵션은 반 깨진입니다. 입력 구분 기호를 지정하기 위해 작동하지만 출력 구분 기호는 항상 쉼표로 하드 코딩됩니다. 손상된 IMO-입력 구분 기호와 동일하거나 사용자가 awk
FS 및 OFS vars와 같이 출력 구분 기호를 설정할 수있는 다른 옵션이 있어야 합니다.
숫자 대신 이름
으로 해당 필드를 참조하려는 경우 다음 을 사용할 수 있습니다 read
.
while read id name age
do
echo "$id $age"
done < file.tsv
나는 마침내 당신의 의미를 보았다! 다음은 명령 행에서 지정한 열만 이름으로 인쇄하는 bash 함수입니다 .
printColumns ()
{
read names
while read $names; do
for col in $*
do
eval "printf '%s ' \$$col"
done
echo
done
}
제시 한 파일과 함께 사용하는 방법은 다음과 같습니다.
$ < file.tsv printColumns id name
1 ed
2 joe
(이 기능은 판독 stdin
. < file.tsv printColumns ...
의 상당 printColumns ... < file.tsv
하고 cat file.tsv | printColumns ...
)
$ < file.tsv printColumns name age
ed 50
joe 70
$ < file.tsv printColumns name age id name name name
ed 50 1 ed ed ed
joe 70 2 joe joe joe
참고 : 요청한 열 이름에주의하십시오! 이 버전은 온 전성 검사가 없으므로 인수 중 하나가 다음과 같은 경우 불쾌한 일이 발생할 수 있습니다."anything; rm /my/precious/file"
id
, name
그리고 age
, 순서가 하드 코딩된다는 사실은 변경되지 않습니다 read
라인.
time { command(s); }
).
time cat temp.txt | ./col1 CHR POS > /dev/null 99.144u 38.966s 2:19.27 99.1% 0+0k 0+0io 0pf+0w time awk -f col2 c1=CHR c2=POS temp.txt > /dev/null 0.294u 0.127s 0:00.50 82.0% 0+0k 0+0io 0pf+0w
그만한 가치가 있습니다. 이것은 선택한 출력 순서에 관계없이 소스에있는 열과 인쇄 할 열을 처리 할 수 있습니다. 그냥 인수를 다시 정렬하십시오 ...
예. 요구:script-name id age
outseq=($@)
colnum=($(
for ((i; i<${#outseq[@]}; i++)) ;do
head -n 1 file |
sed -r 's/ +/\n/g' |
sed -nr "/^${outseq[$i]}$/="
done ))
tr ' ' '\t' <<<"${outseq[@]}"
sed -nr '1!{s/ +/\t/gp}' file |
cut -f $(tr ' ' ','<<<"${colnum[@]}")
산출
id age
1 50
2 70
파일이 당신이 읽고있는이 경우 가능성이 결코 수있는 사용자 생성 할 수 없습니다, 당신은 내장 읽기를 악용 할 수 있습니다 :
f=file.tsv
read $(head -n1 "$f") extra <<<`seq 100`
awk "{print \$$id, \$$age}" "$f"
입력 파일의 첫 번째 전체 행이 인수 목록으로 대체되므로 read
헤더 행의 모든 필드 이름이 변수 이름으로 전달됩니다. 이 중 첫 번째는 seq 100
생성 하는 1을 할당 받고 두 번째는 2를, 세 번째는 3을 얻습니다. 초과 seq
출력은 더미 변수에 의해 흡수됩니다 extra
. 입력 열의 수를 미리 알고 있으면 100을 변경하여 제거 할 수 있습니다 extra
.
awk
스크립트에 의해 정의 된 쉘 변수 수, 이중 인용 문자열 read
로 스크립트로 대체 될 awk
필드 번호를.
단일 열을 선택하는 빠른 방법이 있습니다.
"foo"라는 열을 원한다고 가정 해 봅시다.
f=file.csv; colnum=`head -1 ${f} | sed 's/,/\n/g' | nl | grep 'foo$' | cut -f 1 `; cut -d, -f ${colnum} ${f}
기본적으로 헤더 행을 가져 와서 행당 하나의 열 이름을 가진 여러 행으로 분할하고 행 번호를 지정하고 원하는 이름의 행을 선택한 후 연관된 행 번호를 검색하십시오. 그런 다음 해당 줄 번호를 잘라 내기 명령의 열 번호로 사용하십시오.
이 목적을 위해 기본적으로 다음과 같이 작동하는 Python 스크립트를 작성했습니다.
with fileinput.input(args.file) as data:
headers = data.readline().split()
selectors = [any(string in header for string in args.fixed_strings) or
any(re.search(pat, header) for pat in args.python_regexp)
for header in headers]
print(*itertools.compress(headers, selectors))
for line in data:
print(*itertools.compress(line.split(), selectors))
나는 그것을 호출 hgrep
하기위한 헤더 그렙 이 다음과 같이 사용할 수 있습니다 :
$ hgrep data.txt -F foo bar -P ^baz$
$ hgrep -F foo bar -P ^baz$ -- data.txt
$ grep -v spam data.txt | hgrep -F foo bar -P ^baz$
전체 스크립트는 argparse
명령 행 인수를 구문 분석 하는 데 사용 되며 코드는 다음과 같습니다.
#!/usr/bin/python3
import argparse
import fileinput
import itertools
import re
import sys
import textwrap
def underline(s):
return '\033[4m{}\033[0m'.format(s)
parser = argparse.ArgumentParser(
usage='%(prog)s [OPTIONS] {} [FILE]'.format(
underline('column-specification')),
description=
'Print selected columns by specifying patterns to match the headers.',
epilog=textwrap.dedent('''\
examples:
$ %(prog)s data.txt -F foo bar -P ^baz$
$ %(prog)s -F foo bar -P ^baz$ -- data.txt
$ grep -v spam data.txt | %(prog)s -F foo bar -P ^baz$
'''),
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument(
'-d', '--debug', action='store_true', help='include debugging information')
parser.add_argument(
'file', metavar='FILE', nargs='?', default='-',
help="use %(metavar)s as input, default is '-' for standard input")
spec = parser.add_argument_group(
'column specification', 'one of these or both must be provided:')
spec.add_argument(
'-F', '--fixed-strings', metavar='STRING', nargs='*', default=[],
help='show columns containing %(metavar)s in header\n\n')
spec.add_argument(
'-P', '--python-regexp', metavar='PATTERN', nargs='*', default=[],
help='show a column if its header matches any %(metavar)s')
args = parser.parse_args()
if args.debug:
for k, v in sorted(vars(args).items()):
print('{}: debug: {:>15}: {}'.format(parser.prog, k, v),
file=sys.stderr)
if not args.fixed_strings and not args.python_regexp:
parser.error('no column specifications given')
try:
with fileinput.input(args.file) as data:
headers = data.readline().split()
selectors = [any(string in header for string in args.fixed_strings) or
any(re.search(pat, header) for pat in args.python_regexp)
for header in headers]
print(*itertools.compress(headers, selectors))
for line in data:
print(*itertools.compress(line.split(), selectors))
except BrokenPipeError:
sys.exit(1)
except KeyboardInterrupt:
print()
sys.exit(1)
awk
모든 빈티지에 대해 본질적으로 정수 인덱스입니다 cut
.
다음은 이름 색인 데이터를 처리하도록 설계된 여러 도구입니다 (대부분은 매우 인기있는 파일 형식 인 CSV 및 TSV 만 처리합니다).
이 작은 awk 유틸리티를 사용하여 특정 헤더를 자르십시오-https: //github.com/rohitprajapati/toyeca-cutter
사용법 예-
awk -f toyeca-cutter.awk -v c="col1, col2, col3, col4" my_file.csv
cat
필요하지 않습니다, BTW. 당신은 사용할 수 있습니다awk '{ print $1, $3 }' file.tsv