텍스트 파일의 줄에서 특정 단어를 제거하는 방법?


13

내 텍스트 파일은 다음과 같습니다

Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341

이제 Liquid penetration 95% mass (m)값만 얻기 위해 줄에서 삭제 하고 싶습니다. 어떻게해야합니까?


3
간단히grep -o '[^[:space:]]\+$' file
Avinash Raj

@AvinashRaj : 현재이 솔루션은 '퍼티 메달'을 얻습니다 :)
pa4080

2
@ pa4080 적어도 테스트 한 입력 (10M 라인)에 대해 Avinash Raj의 일반적인 접근 방식 은 PCRE를 사용하여 훨씬 빠르게 진행할 수 있습니다. (GNU grep이 또는을 허용하므로 패턴이 아닌 엔진이 책임이 있음을 확인할 수 \S+$있습니다 .) 따라서 이런 종류의 솔루션은 본질적으로 느리지 않습니다. 그러나 나는 여전히 αғsнιη의 방법에 가까운 곳에서는 그것을 얻을 수 없으므로 벤치 마크얻었 습니다. -E-Pcut
Eliah Kagan

답변:


22

하나의 =부호 만있는 경우 다음을 포함하여 이전과 모든 것을 삭제할 수 있습니다 =.

$ sed -r 's/.* = (.*)/\1/' file
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

원본 파일을 변경하려면 -i테스트 후 옵션을 사용하십시오 .

sed -ri 's/.* = (.*)/\1/' file

노트

  • -r우리가 탈출하지 않아도 ERE를 사용 (하고)
  • s/old/new교체 oldnew
  • .* 임의의 수의 문자
  • (things)저장 things후와 역 참조하는 \1, \2

고맙습니다. 이 명령을 사용하여 기존 파일을 덮어 썼습니다. sed -i -r 's /.*= (. *) / \ 1 /'time.txt 어떻게 작동하는지 설명 할 수 있습니까?
OE

역 참조를 피하십시오. s/^.*= //올바른 값이 줄 끝에 있기 때문에 똑같이 잘 작동합니다.
jpaugh

@jpaugh 잘 부분적으로는 처음 게시 한 내 대답 변경할 너무 늦기 때문에 - 다른 사람이 이미이 경우의 당신이 언급 솔루션 및 기타보다 효율적인 방법을 제공 :하지만 어쩌면 사용하는 방법을 보여주는 한 \1등 사람들을위한 몇 가지 값을 가지고있는 사람 간단한 문제가없는 사람을 검색 할 때이 질문에 답하십시오
Zanna

@Zanna 적어도 더 일반적입니다.
jpaugh

21

이것은 직업입니다 awk; 값이 마지막 필드에서만 발생한다고 가정합니다 (예 :).

awk '{print $NF}' file.txt
  • NFawk변수이며 레코드 (행)의 필드 수로 확장되므로 $NF( $앞의 참고 ) 마지막 필드의 값을 포함합니다.

예:

% cat temp.txt 
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341

% awk '{print $NF}' temp.txt
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

13

여기에 나열된 다양한 솔루션을 비교하기로 결정했습니다. 이를 위해 OP에서 제공 한 내용을 기반으로 큰 파일을 만들었습니다.

  1. 다음과 같은 간단한 파일을 만들었습니다 input.file.

    $ cat input.file
    Liquid penetration 95% mass (m) = 0.000205348
    Liquid penetration 95% mass (m) = 0.000265725
    Liquid penetration 95% mass (m) = 0.000322823
    Liquid penetration 95% mass (m) = 0.000376445
    Liquid penetration 95% mass (m) = 0.000425341
    
  2. 그런 다음이 루프를 실행했습니다.

    for i in {1..100}; do cat input.file | tee -a input.file; done
    
  3. 터미널 창이 차단되었습니다. killall tee다른 터미널에서 실행 했습니다. 그럼 난 명령에 의해 파일의 내용을 조사 : less input.filecat input.file. 마지막 줄을 제외하고는 좋아 보였다. 그래서 마지막 줄을 제거하고 백업 사본을 만들었습니다 cp input.file{,.copy}( inplace 옵션 을 사용하는 명령 때문에 ).

  4. 파일 행의 최종 개수 input.file2 192 473 입니다. 나는 명령으로 그 번호를 얻었다 wc:

    $ cat input.file | wc -l
    2192473
    

비교 결과는 다음과 같습니다.

  • grep -o '[^[:space:]]\+$'

    $ time grep -o '[^ [: space :]] \ + $'input.file> output.file
    
    실제 0m58.539s
    사용자 0m58.416s
    시스 0m0.108s
    
  • sed -ri 's/.* = (.*)/\1/'

    $ sed -ri 's /.* = (. *) / \ 1 /'input.file
    
    진짜 0m26.936s
    사용자 0m22.836s
    시스 0m4.092s
    

    또는 출력을 새 파일로 리디렉션하면 명령이 더 빠릅니다.

    $ sed -r 's /.* = (. *) / \ 1 /'input.file> output.file
    
    실제 0m19.734s
    사용자 0m19.672s
    시스 0m0.056s
    
  • gawk '{gsub(".*= ", "");print}'

    $ time gawk '{gsub ( ". * =", ""); print}'input.file> output.file
    
    실제 0m5.644s
    사용자 0m5.568s
    시스 0m0.072s
    
  • rev | cut -d' ' -f1 | rev

    $ time rev input.file | 컷 -d ''-f1 | rev> output.file
    
    실제 0m3.703s
    사용자 0m2.108s
    시스 0m4.916s
    
  • grep -oP '.*= \K.*'

    $ time grep -oP '. * = \ K. *'input.file> output.file
    
    실제 0m3.328s
    사용자 0m3.252s
    시스 0m0.072s
    
  • sed 's/.*= //' (각각 -i옵션은 명령을 몇 배 느리게 만듭니다)

    $ sed 's /.*= //'input.file> output.file
    
    실제 0m3.310s
    사용자 0m3.212s
    시스 0m0.092s
    
  • perl -pe 's/.*= //' (이 -i옵션은 여기서 생산성에 큰 차이를 일으키지 않습니다)

    $ time perl -i.bak -pe 's /.*= //'input.file
    
    실제 0m3.187s
    사용자 0m3.128s
    시스 0m0.056s
    
    $ time perl -pe 's /.*= //'input.file> output.file
    
    실제 0m3.138s
    사용자 0m3.036s
    시스 0m0.100s
    
  • awk '{print $NF}'

    $ time awk '{print $ NF}'input.file> output.file
    
    실제 0m1.251s
    사용자 0m1.164s
    시스 0m0.084s
    
  • cut -c 35-

    $ 타임 컷 -c 35- input.file> output.file
    
    실제 0m0.352s
    사용자 0m0.284s
    시스 0m0.064s
    
  • cut -d= -f2

    $ 타임 컷 -d = -f2 input.file> output.file
    
    실제 0m0.328s
    사용자 0m0.260s
    시스 0m0.064s
    

아이디어의 원천.


2
그래서 cut -d= -f2솔루션이 이깁니다. haha
αғsнιη

이 파일을 작성하는 방법에 대한 자세한 정보를 제공 할 수 있습니까? 또한 wc -l세 개의 숫자를 어떻게 출력합니까? 다른 옵션이 전달되지 않으면이 옵션은 -l행 수를 제외한 모든 항목을 억제해야합니다.
Eliah Kagan

@EliahKagan, 끝났습니다. 답변을 업데이트했습니다.
pa4080

아, 알다시피-공백은 숫자 그룹 구분 기호였습니다. ( wc실제로 해당 공간을 표시 했습니까? 로케일 설정이 있습니까?) 업데이트 주셔서 감사합니다!
Eliah Kagan

@EliahKagan : 마지막으로 wc한 번 더 질문을 읽 습니다. 나는 오늘 나의 지혜가 어디에서 왔는지 모른다. 그러나 나는 그것을 정말로 이해할 수 없었다. 실제로 공백은 숫자 그룹 구분 기호 이며 wc추가하지 않았습니다. :
pa4080

12

grep상기 -P갖는 대 PCRE(A와 패턴 해석 P erl- C ompatible R egular E 및 xpression) -o만을 인쇄 유사한 패턴. 는 \K일치하는 부분은 자신 앞에 오는 무시합니다 통지합니다.

$ grep -oP '.*= \K.*' infile
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

또는 cut대신 명령을 사용할 수 있습니다 .

cut -d= -f2 infile

2
실행하는 것 외에도 가장 빠른에서 테스트 한 모든 방법 pa4080의 벤치 마크 , 이 답변의 방법은 도에서 확실한 승자였다 내가 달릴 작은 벤치 마크 그 테스트 적은 방법을하지만, 더 큰 입력 파일을 사용했다. 개인적으로 좋아하는 방법의 빠른 변형보다 10 배 이상 빠릅니다 (그리고 내 대답은 주로 관련되어 있습니다). cut
Eliah Kagan

11

행 접두사는 항상 같은 길이 (34 자)이므로 다음을 사용할 수 있습니다 cut.

cut -c 35- < input.txt > output.txt

6

을 사용하여 파일의 내용을 rev바꾸고 출력을 cut구분 기호로 공백과 대상 필드로 1로 파이프 한 다음 다시 뒤집어 원래 숫자를 얻습니다.

$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

5

이것은 간단하고 짧으며 작성, 이해 및 확인이 쉽고 개인적으로 좋아합니다.

grep -oE '\S+$' file

grep우분투에서 호출 할 때, -E또는 -P의 소요 속기 \s 비열한하는 공백 문자를 (실제로는 일반적으로 공백이나 탭)과 \S하나가 아닌 평균 아무것도. 사용 수량 어+행의 끝 앵커$ , 패턴은 \S+$라인의 단부에 하나 이상의 비 - 블랭크 일치 . -P대신에 사용할 수 있습니다 -E; 이 경우 의미 는 동일하지만 다른 정규식 엔진 이 사용되므로 성능 특성이 다를 수 있습니다 .

이것은 Avinash Raj의 논평 솔루션 과 동일합니다 (더 쉽고 간결한 구문으로).

grep -o '[^[:space:]]\+$' file

후행 공백이있을 수 있다면이 방법이 작동하지 않습니다 후에 수. 그것들은 그렇게 할 수 있도록 수정 될 수 있지만, 여기서는 아무런 의미가 없습니다. 더 경우에 따라 작업에 대한 해결책을 일반화 때로는 교훈 비록 하나는 일반적으로 알 수있는 방법이 없기 때문에, 그것은, 그래서 거의 자주 사람들이 생각하는 경향이 할 실용적이지의 다양한 호환되지 않는 방법으로있는 문제가 궁극적으로해야 할 수도 있습니다를 일반화되다.


때로는 성능이 중요한 고려 사항입니다. 이 질문은 입력이 매우 크다고 명시하지 않으며 여기에 게시 된 모든 방법이 충분히 빠를 수 있습니다. 그러나 속도가 필요한 경우 천만 줄 입력 파일에 대한 작은 벤치 마크가 있습니다.

$ perl -e 'print((<>) x 2000000)' file > bigfile
$ du -sh bigfile
439M    bigfile
$ wc -l bigfile
10000000 bigfile
$ TIMEFORMAT=%R
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
819.565
$ time grep -oE '\S+$' bigfile > bigfile.out
816.910
$ time grep -oP '\S+$' bigfile > bigfile.out
67.465
$ time cut -d= -f2 bigfile > bigfile.out
3.902
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
815.183
$ time grep -oE '\S+$' bigfile > bigfile.out
824.546
$ time grep -oP '\S+$' bigfile > bigfile.out
68.692
$ time cut -d= -f2 bigfile > bigfile.out
4.135

순서가 문제가되는 경우 (때로는 I / O가 많은 작업에서와 같이) 두 번 실행했으며 백그라운드에서 다른 작업을 수행하지 않는 기계가 없기 때문에 결과가 왜곡 될 수 있습니다. 그 결과로부터 나는 적어도 임시적으로 그리고 내가 사용한 크기의 입력 파일에 대해 다음을 결론 지었다.

  • 와! 전달 -P(사용에 PCRE 가 아닌) -G또는 (더 방언이 지정되지 않은 기본) -E만들어진 grep크기 순서를 통해 빠르게하여. 따라서 큰 파일의 경우 위에 표시된 것보다이 명령을 사용하는 것이 좋습니다.

    grep -oP '\S+$' file
  • 와!! cut의 방법 αғsнιη의 대답은 , , 빨리 내 방식의 경우에도 빠른 버전보다 크기 순서 이상입니다! pa4080의 벤치 마크에서도이 방법비해이 방법보다 더 많은 방법을 다루었지만 입력이 더 적으므로 다른 모든 방법 중에서 테스트에 포함시키기 위해이 방법을 선택했습니다. 성능이 중요하거나 파일이 크면 αғsнιη의 방법을 사용해야 한다고 생각 합니다.cut -d= -f2 filecut

    이것은 또한 간단한 도구 cutpaste유틸리티 를 잊어서는 안된다는 것을 상기 시키는 역할을하며 , grep종종 일차 솔루션으로 제공되는 것과 같은보다 정교한 도구가 있지만 개인적으로 더 익숙해 져도 적용 가능할 때 선호되어야합니다 사용).


4

perl- S는 패턴 ubstitute /.*= /빈 문자열을 //:

perl -pe 's/.*= //' input.file > output.file
perl -i.bak -pe 's/.*= //' input.file
  • 보낸 사람 perl --help:

    -e program        one line of program (several -e's allowed, omit programfile)
    -p                assume loop like -n but print line also, like sed
    -i[extension]     edit <> files in place (makes backup if extension supplied)
    

sed -패턴을 빈 문자열로 대체하십시오.

sed 's/.*= //' input.file > output.file

또는 (그러나 위보다 느림) :

sed -i.bak 's/.*= //' input.file
  • Zanna의 답변 보다 몇 배 빠르기 때문에이 방법을 언급했습니다 .

gawk-패턴 ".*= "을 빈 문자열로 대체하십시오 "".

gawk '{gsub(".*= ", "");print}' input.file > output.file
  • 보낸 사람 man gawk:

    gsub(r, s [, t]) For each substring matching the regular expression r in the string t,
                     substitute the string s, and return the number of substitutions. 
                     If t is not supplied, use $0...
    
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.