입력(여러 줄):
abc def ghi 123 345 456
abc def def ghi 123 345 456
abc def def def ghi 123 345 456
출력(한 줄에서 한 줄로 문자열/정규식 추출):
def 345
def def 345
def def def 345
첫 번째...
echo "abc 123" | grep -Po "\Kabc|\K123"
하지만 이렇게 하면 두 줄이 인쇄됩니다.
abc
123
두번째:
echo -ne "abc def bac 123\nabc def def bac 123\nabc def def def bac 123 123\n" | grep -Po "def|123" | paste -d ' ' - -
그러나 이는 다음을 보여줍니다.
def 123
def def
123 def
def def
123 123
제 생각에는:
def 123
def def 123
def def def 123 123
\n을 제거하기 위해 tr을 사용할 수 없습니다. def 또는 345는 한 줄에서 여러 번 발견될 수 있으며 다른 모든 줄을 제거하는 \n은 의미가 없습니다. 열 구분 기호를 사용할 수 없습니다.
답변1
그리고perl
$ cat ip.txt
abc def ghi 123 345 456
abc def def ghi 123 345 456
abc def def def ghi 123 345 456 1234
$ perl -lane 'print join " ", grep { /def|123/ } @F' ip.txt
def 123
def def 123
def def def 123 1234
$ perl -lane 'print join " ", grep { $_ eq "def" || $_ eq "123" } @F' ip.txt
def 123
def def 123
def def def 123
-lane
여기서는-l
입력 줄에서 줄 바꿈을 제거하고print
사용할 때 다시 추가하고,-a
입력 줄을 공백으로 자동으로 분할하고 결과를@F
배열에 저장하고,-n
입력 줄을 반복하지만 처리 후 줄을 자동으로 인쇄하지 않고-e
명령에서 허용합니다 . Perl 스크립트 라인 제공grep { /def|123/ } @F
또는@F
를 포함하는 경우 배열의 모든 요소를 필터링합니다 .def
123
- 정규식 대신 문자열 일치를 원하면 다음을 사용할 수 있습니다.
grep { $_ eq "def" || $_ eq "123" } @F
- 정규식 대신 문자열 일치를 원하면 다음을 사용할 수 있습니다.
print join " "
grep
공백을 구분 기호로 사용하여 출력에서 얻은 요소를 인쇄합니다.
답변2
ex
다음과 함께 사용 awk
:
$ cat test.txt
abc def ghi 123 345 456
abc def def ghi 123 345 456
abc def def def ghi 123 345 456
$ printf '%s\n' 'g/^/.!awk -v ORS=" " -v RS=" " "/^(def|345)$/"' %p | ex test.txt
def 345
def def 345
def def def 345
$
그 기능은 다음과 같습니다:
ex
수정, 인쇄 및/또는 저장할 수 있는 버퍼(in)로 파일을 읽습니다 .awk
스크립트를 통해 버퍼의 각 라인을 (개별적으로) 필터링합니다.- 버퍼의 전체 내용을 인쇄합니다( 를 사용하여
%p
).
위 명령은 결과를 파일에 다시 저장하지 않습니다. 이렇게 하려면 %p
으로 바꾸면 됩니다 x
.
더 자세한 설명:
ex
스크립트 가능한 파일 편집기입니다. 파일 이름( test.txt
)을 인수로 받아들이고 표준 입력에서 편집 명령을 가져옵니다.
여기서는 사용된 편집 명령을 제공합니다 printf
. 첫 번째 매개변수 는 나머지 매개변수가 출력되는 방식을 제어하는 printf
형식 문자열(이 경우 )입니다 . 모든 매개변수는 문자열이고 각 매개변수 뒤에 개행 문자가 인쇄되어야 한다고 말합니다. (작은 따옴표는 쉘이 백슬래시를 해석하는 것을 피하기 위해 존재합니다. 우리는 쉘이 아닌 백슬래시를 얻고 싶습니다.)'%s\n'
printf
printf
ex
을 사용하여 두 개의 매개변수를 보냅니다 printf
. 여기 그들이 온다:
g/^/.!awk -v ORS=" " -v RS=" " "/^(def|345)$/"
%p
그 중 두 번째가 가장 간단합니다. %
주소 범위입니다. 이는 "전체 버퍼"를 의미합니다. p
인쇄 명령입니다. 따라서 이는 "전체 버퍼 인쇄"를 의미합니다.
첫 번째는 약간의 분해가 필요합니다.
g/.../
"전역" 명령입니다. 전체 버퍼에서 주어진 패턴(이 경우 ^
"줄의 시작"을 의미하는 정규식)과 일치하는 줄을 검색하고 ex
해당 줄마다 다음 편집 명령을 실행합니다. 각 줄에는 줄 시작이 있으므로 모든 줄이 일치하므로 ^
각 줄에서 다음 명령을 별도로 실행하는 효과가 있습니다.
그런 다음 .
"(버퍼의) 현재 라인"을 의미하는 주소가 있습니다. 명령어 뒤에 나오므로 g
버퍼의 각 라인을 차례로 참조한다.
!
쉘 명령을 실행하는 데 사용됩니다. 주소가 앞에 붙으면(이 경우 .
), 주어진 줄 범위(또는 단일 줄)가 주어진 쉘 명령에 제공됩니다.표준 입력명령의 결과(표준 출력)는 해당 라인의 버퍼에 배치됩니다.
즉, .!shell-command-here
in은 ex
일부 외부 명령을 통해 버퍼의 현재 라인을 필터링하는 것을 의미합니다.
우리는 이미 이 명령 설정이 명령으로 버퍼의 각 행을 (개별적으로) 필터링하는 방법을 다루었습니다. awk
이제 명령을 분석해 보겠습니다 awk
.
awk -v ORS=" " -v RS=" " "/^(def|345)$/"
awk
이 플래그를 사용하여 변수를 정의할 수 있습니다 -v
. 따라서 처음 몇 개의 매개변수 는 ORS
및 RS
변수를 단일 공백 문자로 설정합니다.
RS
in은 awk
"레코드 구분 기호"입니다. 기본적으로 해당 값은 개행 문자입니다. 설정된 문자는 awk
읽을 때 레코드(일반적으로 줄)를 구분하는 데 사용됩니다.
마찬가지로, ORS
출력 레코드 구분자는 awk
출력을 인쇄할 때 레코드(일반적으로 줄)를 구분하는 데 사용되는 항목을 제어합니다.
각 단어를 공백 문자로 설정하면 줄의 각 단어를 단일 레코드로 쉽게 작업할 수 있습니다.
다음 부분은 실제 awk
명령입니다. ( awk
자체 스크립팅 언어입니다.) awk
명령 블록은 조건과 동작으로 구성됩니다. 여기서 조건은 /.../
정규식 일치입니다. 즉, 조건은 주어진 정규식과 일치하는 모든 레코드(이 경우 단어)에 적용됩니다. 정규식 부분은 ^
(문자열의 시작), $
(문자열의 끝)이며, 두 가지 가능한 패턴은 괄호 안에 그룹화되고 |
(파이프라인)으로 구분되어 이러한 패턴 중 어느 것이든 허용 가능함을 나타냅니다.
조건 뒤에는 액션이 없으므로(액션은 중괄호 안에 표시됨 awk
) awk의 기본 액션 "print"는 조건과 일치하는 레코드에 적용됩니다. (이것은 해당 줄에 대해 일치하는 각 레코드(단어)가 인쇄된 다음 해당 출력이 읽혀지고 awk
처음 입력된 ex
버퍼의 줄 위치에 배치된다는 것을 의미합니다.)ex
awk
이 솔루션은 모든 패턴이 완전한 단어와 일치한다는 단순화된 가정을 합니다. 즉, 다음 패턴 중 어느 것과도 일치하지 않으려고 합니다.포함하다공백. 이는 질문에 제공한 입력 예시와 일치합니다.
답변3
awk
원하는 필드만 사용하고 유지할 수 있습니다 .
echo -e "abc def bac 123\nabc def def bac 123\nabc def def def bac 123 123" \
| awk -v var1="def" -v var2="123" '{
i=0
for (j=1; j<=NF; j++){
if ($j==var1 || $j==var2){ $++i=$j }
if (i!=j){ $j="" }
}
print
}'
이는 for 루프의 필드를 반복하고 def
또는 123
다음 필드에 다시 할당합니다 $++i=$j
(인덱스 0에서 시작하므로 첫 번째 필드는 1이고 다음 필드는 2입니다...). 인덱스가 비어 있으면 재설정됩니다. $j
빈 문자열( $j=""
) 에 대한 현재 필드 i
는 순환 인덱스가 아닙니다 j
.
산출:
def 123
def def 123
def def def 123 123