sed 명령을 사용하여 리눅스에서 각 줄의 마지막 단어를 인쇄 할 수 있습니까?


9

다음 행으로 구성된 파일이있는 경우

12345567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65y7 y66uyuy

 yy46y6y

출력은 다음과 같아야합니다.

66

y6y46y

y5y

y66uyuyy

y46y6y

명령 sed 's/.* //g'파일 이름과 다른 여러 명령을 시도했지만 sed작동하지 않습니다.

정확한 sed명령 이 무엇인지 알 수 있습니까 ?


반드시 사용해야 sed합니까?
coffeMug

답변:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

빈 줄마다 빈 줄이 인쇄됩니다. 그것을 피하려면 :

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

단일 표현 대안 : sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'.
jimmij

@jimmij-마지막 비 공백 시퀀스도 첫 번째이고 그 앞에 공백이 없으면 작동하지 않습니다. 또한 .*꼬리에서 할 수도 있습니다 . 아마도 후행 공백을 제외한 모든 것을 배제합니다 .*[^[:blank:]].
mikeserv


4

당신은 시도 할 수 있습니다 :

  • sed 's/.* //'
  • awk '{print $NF}'

4

거의 다 왔습니다. 마지막 단어를 지정하십시오.

sed 's/^.* \([^ ][^ ]*\)/\1/g'

그것이하는 일 :

  1. '^. *'는 줄의 시작 부분과 공백을 모두 삭제합니다.
  2. '\ (...) \'는 패턴과 일치하여 \ 1로 반환합니다.
  3. '[^]'는 공백이없는 것과 일치합니다.

(더 나은 솔루션을 추가하기 위해 편집했습니다. 감사합니다. Hildred!)


1
다음은 더 짧은 표현식입니다. sed -r 's/.* ([^ ]+)/\1/g'확장 된 정규 표현식이 허용되는 경우 일반적입니다.
mkalkov

더 짧은 버전, 당신이 유지하기를 원치 않는 것을 대체하여 사용하기 :sed 's/.* //'
Uriel

2

예를 들어, grep대신에 적절한 패턴을 사용할 수 있습니다 sed.

grep -o "[a-Z0-9]*$"

이 예에서, [...]"word"에 적합한 것으로 간주되는 문자 범위를 포함합니다 (이 경우 영숫자, 다른 기호를 추가 할 수 있으며 일부는 이스케이프해야 함).


3
줄 끝에 공백이 없다고 가정합니다. a-ZASCII 기반 로케일에서도 범위가 의미가 없습니다. 참고 -oGNU 확장이다.
Stéphane Chazelas

0

1 개 이상의 공백이 아닌 문자 시퀀스 를 의미 하도록 단어 를 한정 하면 대답은 확실히 그렇습니다. 아주 간단하게 수행됩니다. 때문입니다 및 문자열의 모든 문자를 제공 완료 - - 부울 보완하고는 U가 거의 같은 방법으로 가능한 모든 문자열을 설명 할 수 않습니다.[[:blank:]]*[^[:blank:]]*[[:blank:]]*[^[:blank:]]*.*

불완전한 문자 또는 유효하지 않은 바이트 시퀀스가 ​​문자열 내에 존재하는 경우, 잘못된 인코딩으로 문자열을 해석 할 때 때때로 발생할 수있는 것처럼이를 머리부터 꼬리까지 성공적으로 설명 할 수 없습니다. 모든 문자열에서 바이트 당 완전한 문자를 보장하기 위해 C 로케일은 다음과 같이 강제 될 수 있습니다.

LC_ALL=C sed ...

... .*또는 과 같은 포괄적 인 패턴으로 머리부터 꼬리까지 문자열을 설명하는 문제를 피할 수 있습니다.([ ]*[^ ]*)*

완전 보완 패턴은 패턴의 끊김없이 마지막 발생시 착륙 할 문자열의 길이를 왼쪽에서 오른쪽으로 여러 번 반복 할 수 있습니다. 이것은 확실히 정규 언어입니다.

BRE :

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

오히려:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

이 두 버전 모두 여전히 빈 줄을 인쇄하며 이는 Kleene *별이 0 개 이상의 패턴 발생과 일치 하기 때문 입니다. 먼저 공백 문자가 아닌 0 개 이상, 공백 문자가 0 개 이상, 문자열이 완전히 일치 할 때까지 그룹화 된 일치 항목이 0 개 이상 일치합니다.

이 모든 일치하는 데, 마법 교체에서 일어나는 - 참조가 그룹에 의해 반환 \1하고 \2각각의 마지막 발생합니다. 따라서 대체 할 때 모든 문자열은 0 개 이상의 빈 문자가 아닌 행 또는 하위 그룹의 마지막 행으로 만 바뀝니다 \2.

물론 이것은 가능한 문자열-심지어 비어있는 문자열에서 작동합니다. 즉, 두 형식 모두 공백 문자 만 포함하거나 전혀 포함하지 않는 행에 대해 줄 바꿈 문자를 인쇄합니다. 이를 처리하기 위해 몇 가지 작업을 수행 할 수 있지만 먼저 문자 클래스를 좀 더 쉽게 입력 할 수 있습니다.

b='[:blank:]'

이제 한 줄에 공백이 아닌 문자가 하나 이상 포함 된 경우에만 인쇄하려면 다음을 수행하십시오.

BRE :

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

오히려:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. BRE 경우-대체는 항상 수행되며 하나 이상의 문자가 남은 패턴 공간 만 인쇄됩니다.
  2. ERE 경우-공백 문자가 아닌 하나 이상의 패턴 공간에서만 대체가 시도됩니다.

구문이 올바른 경우 어느 형식이든 어느 방법 으로든 작동합니다.

-n패턴 공간의 스위치 비활성화 인쇄 자동 및 p받는 플래그 s///ubstitution 또는 /주소 /명령의 결과를 경우에만 성공적으로 인쇄합니다.

다음과 같이 동일한 논리를 적용하여 모든 {num}발생 을 얻을 수 있습니다 .

BRE :

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

오히려:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

여기서 num두 정규 표현식의 숫자는 숫자로 대체되어 {num}공백 문자가 아닌 일련의 지정된 항목 만 인쇄 할 수 있습니다 . 여기에서는 문자열의 선행 공간에 대해 카운트가 기울어지지 않도록 약간 다른 형식이 사용됩니다.

참고 그 -E에게 ERE 스위치 sed가 아니지만, BSD와 GNU 버전 모두 지원됩니다 아직 POSIX 표준 구문.


멋진 설명, 좋은 해킹,하지만주의 그것을 의지하지 작업 기존의 sed 구현 (같은 솔라리스는 / usr / 빈 / 나오지도)과 함께 25 명 이상의 자 입력 라인 더 간단한 방법 (배기 메모리보다 더 비싼 것입니다 sed_su3인스턴스의 주얼리 toolchest을에서). 따라서 대답이 마음에 들지만 그 방법을 권장하지 않습니다.
Stéphane Chazelas

FreeBSD에서도 작동하지 않는 것 같습니다.
Stéphane Chazelas

@ StéphaneChazelas-예, 성능은 이와 같은 경우 정말 끔찍하지만 번호가 매겨진 항목을 선택하는 데 매우 효과적 일 수 있습니다. 그리고 줄 끝의 경우 s/.* \([^[:blank:]]\{1,\}\).*/\1/가 훨씬 낫지 만 여러 줄이 관련되어 있으면 더 어렵습니다. 그러나 다른 날, 나는 그것을 's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]효과적으로 효과적으로 뛰어 올릴 수 있음을 발견 했습니다. 어쨌든, 논리에 눈부신 오류가 없다면 행복합니다-나는 무언가를 놓친 것 같아요.
mikeserv

@ StéphaneChazelas-그리고 오래된 sedS 에 관해서는 – 조금 이상합니다-표준에 따라 소리가 나야합니다. xrat는 말합니다. 표준 개발자들은 공통적 인 과거 행동을 지원 "\n*"했지만, 그렇지 않은 "\n\{min,max\}", "\(...\)*"경우 또는 "\(...\)\{min,max\}"특정 구현의 의도하지 않은 결과로 간주했으며 하위 표현식과 역 참조에 따른 복제 및 간격 표현식을 모두 지원했습니다.
mikeserv

@ StéphaneChazelas-그리고 표준에 따르면 ... 역 참조에 의해 참조되는 하위식이 별표 ( '*' )또는 구간 표현식으로 인해 하나 이상의 문자열과 일치하는 경우 (항목 (5) 참조) 역 참조는 마지막 (가장 오른쪽)과 일치해야합니다. )를이 문자열의 그래도 내가 이것을 테스트 minised했다고 확신합니다 -확실히 나는 minised다른 날에 이상한 것을 테스트하고있었습니다 .
mikeserv

0
sed 's/^ star.star //'  filename  or sed 's/^[[:blank:]]star.star[[:blank:]]//' filename

분석:

  • s -대체

  • / -찾을 표현의 시작

  • ^ -줄의 처음부터

  • [[:blank:]]* -줄의 시작 부분에 공백이있는 경우

  • .* -어떤 캐릭터

  • [[:blank:]] -그리고 공백 문자

  • / -대체 할 표현의 시작

  • / -명령 구문의 끝

추신 : 나는 명령에 별을 썼다.


이것이 질문에 주어진 데이터에 어떻게 적용됩니까?
Kusalananda

s/.*[[:blank:]]//줄 끝에 공백이 없으면 @Scott 가 작동합니다.
Kusalananda

-1

예. 다음 sed 명령은 먼저 모든 후행 공백 ( s/ *$//)과 마지막 공백 ( s/.* //)을 포함하여 모든 공백을 제거합니다 . [[:blank:]]탭 및 기타 공백과 같은 문자를 캡처하기 위해 리터럴 공백을 대체하는 것이 좋습니다 .

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.