명령줄에서 필드 기반 데이터를 조작하는 방법은 무엇입니까? 예를 들어
- N번째 필드가 있는 행만 인쇄하는 방법은 무엇입니까
foo
? - N번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까
foo
? - N번째 필드가 일치하는 행만 인쇄하는 방법은 무엇입니까
foo
? - N 필드를 로 어떻게 변경합니까
foo
?
*nix 시스템에서 현장 기반 데이터를 조작하는 데 도움이 되는 표준 방법론이나 도구 세트가 있습니까?
답변1
필드 작업 시 사용할 수 있는 두 가지 기본 접근 방식은 다음과 같습니다. i) 필드를 이해하는 도구 사용 ii) 정규식 사용. 둘 중 전자가 일반적으로 더 강력하고 간단합니다.
*nix의 많은 일반적인 도구는 필드를 처리하도록 명시적으로 설계되었거나 이를 용이하게 하는 영리한 트릭을 가지고 있습니다.
1. 분야를 이해하는 도구를 사용하세요
1.1아크
여기서의 고전적인 도구는 awk
각 입력 줄을 자동으로 필드로 분할한 다음(필드 구분 기호는 기본적으로 공백이지만 플래그를 사용하여 변경할 수 있음 ) 아래와 같이 -F
이러한 필드를 스크립트에서 사용할 수 있습니다.awk
$n
n
필드 번호입니다. 첫 번째 필드는 이고 $1
, 두 번째 필드는 $2
이런 식입니다.
세 번째 필드가 있는 줄을 인쇄합니다
foo
.awk '$3=="foo"' file
구분 기호를 다음으로 변경하십시오.
:
awk -F":" '$3=="foo"' file
기본 작업은
awk
인쇄입니다. 따라서 위 명령은 세 번째 필드가 있는 모든 줄을 인쇄합니다foo
. 를 사용하면-F
필드 구분 기호를 설정하고 정규식을 사용할 수도 있습니다.세 번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까
foo
?awk '$3!="foo"' file
세 번째 필드가 일치하는 행만 인쇄하는 방법은 무엇입니까
foo
?foo
패턴과 일치하는 필드(예: matchfoobar
) 를 찾고 있다면~
대신 다음 을 사용하세요==
.awk '$3~/foo/' file
세 번째 필드가 일치하지 않는 행만 인쇄하려면 어떻게 해야 합니까
foo
?awk '$3!~/foo/' file
세 번째 필드를 로 어떻게 변경합니까
foo
?awk '$3="foo"' file
1.2 펄
또 다른 옵션은 perl
한 줄입니다. awk와 마찬가지로 Perl은 모든 기능을 갖춘 스크립트 언어이지만 스크립트를 입력으로 사용하여 명령줄 프로그램으로 실행할 수도 있습니다. 동작은 명령줄 스위치를 통해 수정되며, 이 질문과 가장 관련이 있는 스위치는 다음과 같습니다.
-e
perl
: 실행되어야 하는 스크립트입니다.-n
: 입력 파일을 한 줄씩 읽습니다.-p
:Apply; 주어진 스크립트 다음에 각 입력 줄을 인쇄합니다-e
.-l
print
:각 입력 줄에서 후행 줄 바꿈을 제거하고 각 호출에 줄 바꿈을 추가합니다.-a
:awk-mode, 각 입력 라인을 배열로 분할합니다@F
.-F
: 필드 구분 기호-a
.
한 가지 중요한 차이점 은 스위치가 파일을 배열로 분할한다는 것 awk
입니다 . Perl에서는 배열이 1이 아닌 0부터 시작합니다. 즉, 두 번째 필드는 실제로 가 아닙니다 . 이 모든 것을 고려하면 위의 내용은 다음과 같습니다.perl
-a
$F[1]
$F[2]
perl
세 번째 필드가 있는 줄을 인쇄합니다
foo
.perl -ane 'print if $F[2] eq "foo"' file
구분 기호를 다음으로 변경하십시오.
:
perl -F":" -ane 'print if $F[2] eq "foo"' file
awk
와 달리perl
정규식을 필드 구분 기호로 사용할 수 없습니다. 특정 문자나 문자열이어야 합니다.세 번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까
foo
?perl -ane 'print unless $F[2] eq "foo"' file
세 번째 필드가 일치하는 행만 인쇄하는 방법은 무엇입니까
foo
?perl -ane 'print if $F[2]=~/foo/' file
세 번째 필드가 일치하지 않는 행만 인쇄하려면 어떻게 해야 합니까
foo
?perl -lane 'print unless $F[2]=~/foo/' file
세 번째 필드를 로 어떻게 변경합니까
foo
?Perl에서는 이것이 약간 문제가 됩니다. 일반적인 접근 방식은 배열의 값을 변경한
@F
다음 배열을 인쇄하는 것입니다. 간단한 공백으로 구분된 파일의 경우 다음과 같이 쉽습니다.perl -lane '$F[2]="foo"; print "@F"' file
다른 구분 기호를 사용하면 배열이 필요합니다
join
. 그렇지 않으면 공백으로 구분되어 인쇄됩니다.perl -F: -lane '$F[2]="foo"; print join ":",@F' file
2. 정규식을 사용하세요
여기서의 아이디어는 정규식(줄여서 "regex")을 사용하여 줄에서 대상 문자열의 위치를 정의하는 것입니다. 예를 들어 필드가 로 구분된 파일에서 :
첫 번째 필드(첫 번째 필드) 앞의 모든 항목을 일치시킨 :
다음 두 번째 필드를 찾아 두 번째 필드를 찾을 수 있습니다.
^[^:]*:[^:]*:
이 정규 표현식의 의미는 다음과 같습니다.
^
: 줄의 시작;[^]
: 부정된 문자 클래스입니다.[^:]
":
이외의 것"을 의미합니다.*
: 0개 이상의 이전 패턴;:
:문자 그대로의 의미:
;
전체적으로 이는 첫 번째 [^:]*
필드가 첫 번째 필드이고 두 번째 필드가 두 번째 필드임을 의미합니다. 분명히 이것은 14번째 필드를 찾는 경우 그다지 실용적이지 않지만 더 간단한 작업에는 유용합니다. 그렇다면 데이터를 조작하기 위해 이를 어떻게 구현합니까? 이를 수행하는 데는 다양한 도구가 있습니다. 이 예에서는 를 사용 sed
하지만 을 사용 awk
하거나 perl
매우 유사한 작업을 수행 할 수도 있습니다 python
.
두 번째 필드가 있는 행만 인쇄하려면 어떻게 해야 합니까
foo
?sed -n '/^[^:]*:foo:/p' file
-n
일반 출력을 억제합니다 ./regex/p
즉, "정규식과 일치하는 모든 줄을 인쇄합니다.두 번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까
foo
?sed '/^[^:]*:foo:/d' file
위의 논리와 반대입니다. 여기서는
/regex/d
"정규식과 일치하는 모든 줄을 제거합니다."를 의미합니다.두 번째 필드가 일치하는 행만 인쇄하려면 어떻게 해야 합니까
foo
?sed -n '/^[^:]*:[^:]*foo/p' file
두 번째 필드가 일치하지 않는 행만 인쇄하려면 어떻게 해야 합니까
foo
?sed '/^[^:]*:[^:]*foo/d' file
두 번째 필드를 로 어떻게 변경합니까
foo
?sed 's/\([^:]*:\)[^:]*/\1foo/' file
또는 대체는
sed
간단한 숫자 플래그 반복을 사용하여 패턴 발생을 직접 해결할 수 있으므로 다음과 같습니다.sed 's/[^:]*/foo/2' file