파이프라인에서 여러 tr 프로세스를 피하기 위해 tr 명령을 연결하는 것이 가능합니까?

파이프라인에서 여러 tr 프로세스를 피하기 위해 tr 명령을 연결하는 것이 가능합니까?

여러 개의 txt 파일이 있는데 이를 소문자, 알파벳 순으로 한 줄에 한 단어씩 출력하고 싶습니다. tr다음과 같이 파이프라인에서 여러 명령을 사용하여 이 작업을 수행할 수 있습니다.

tr -d '[:punct:]' <doyle_sherlock_holmes.txt | tr '[:upper:]' '[:lower:]' | tr ' ' '\n'

한 번의 스캔으로 완료할 수 있나요? 이를 위해 C 프로그램을 작성할 수도 있지만 tr, sed또는 를 사용하여 awk이를 수행할 수 있는 방법이 있는 것 같습니다 perl.

답변1

여러 번역을 결합할 수 있지만(로케일 관련 세트가 겹치는 복잡한 경우 제외) 삭제와 번역을 결합할 수는 없습니다.

<doyle_sherlock_holmes.txt tr -d '[:punct:]' | tr '[:upper:] ' '[:lower:]\n'

더 복잡한 도구의 경우 두 번의 호출이 tr한 번의 호출보다 빠를 수 있지만 이는 입력 크기, 다양한 문자의 비율, 도구 구현 tr및 경쟁 도구, 운영 체제, 코어 수 등에 따라 크게 달라집니다.

답변2

예. trASCII 로케일에서 이 작업을 수행 할 수 있습니다.(GNU의 경우 어쨌든 tr이것이 유일한 권한입니다). POSIX 클래스를 사용하거나 8진수로 각 문자의 바이트 값을 참조할 수 있습니다. 범위에 걸쳐 변환을 분할할 수도 있습니다.

LC_ALL=C tr '[:upper:]\0-\101\133-140\173-\377' '[:lower:][\n*]' <input

위 명령은 모든 대문자를 소문자로 변환하고, 소문자를 완전히 무시하고, 다른 모든 문자를 개행 문자로 변환합니다. 물론 빈 줄이 많이 생길 것입니다. 이 경우 압착 반복 스위치가 유용할 수 있지만 tr -sto 변환과 함께 사용하면 결국 대문자도 압착하게 됩니다. 이렇게 하면 여전히 다음과 같은 두 번째 필터가 필요합니다.[:upper:][:lower:]

LC... tr ... | tr -s \\n

...또는...

LC... tr ... | grep .

...결국 이렇게 하는 것보다 훨씬 편리해집니다...

LC_ALL=C tr -sc '[:alpha:]' \\n <input | tr '[:upper:]' '[:lower:]'

...이것은 -c알파벳 문자의 2개의 보수를 단일 개행 문자로 순차적으로 압축한 다음 파이프의 다른 쪽에서 위에서 아래로 변환을 수행합니다.

그렇다고 이러한 성격의 범위가 유용하지 않다는 것은 아닙니다. 이 같은:

tr '\0-\377' '[1*25][2*25][3*25][4*25][5*25][6*25][7*25][8*25][9*25][0*]' </dev/random

...입력 바이트를 해당 값의 확산 스펙트럼 내의 모든 숫자로 변환하므로 매우 편리할 수 있습니다. 낭비하지 말고, 원하지도 마세요.

변환을 수행하는 또 다른 방법에는 dd.

tr '\0-\377' '[A*64][B*64][C*64][D*64]' </dev/urandom |
dd bs=32 cbs=8 conv=unblock,lcase count=1

dadbbdbd
ddaaddab
ddbadbaa
bdbdcadd

작업 과 변환을 동시에 dd수행할 수 있으므로 대부분 의 작업을 여기에 맡길 수도 있습니다. 그러나 이는 단어당 바이트 수를 정확하게 예측할 수 있거나 적어도 각 단어에 공백을 미리 채워 예측 가능한 바이트 수를 달성할 수 있는 경우에만 유용합니다. 왜냐하면 이것이 각 블록 공간의 후행 끝을 차지하기 때문입니다.unblocklcaseunblock

답변3

다음은 몇 가지 방법입니다.

  • GNU grepSum tr: 모든 단어를 찾아 소문자로 만듭니다.

    grep -Po '\w+' file | tr '[A-Z]' '[a-z]'
    
  • GNU grep 및 perl: 위와 동일하지만 Perl은 소문자 변환을 처리합니다.

    grep -Po '\w+' file | perl -lne 'print lc()'
    
  • perl: 모든 알파벳 문자를 찾아 소문자로 인쇄합니다(@steeldriver에게 감사드립니다):

    perl -lne 'print lc for /[a-z]+/ig' file
    
  • sed: 문자나 공백이 아닌 모든 문자를 제거하고 모든 알파벳 문자를 소문자 버전으로 바꾸고 모든 공백을 줄 바꿈으로 바꿉니다. 이는 모든 공백이 공백이고 탭이 없다고 가정합니다.

    sed 's/[^a-zA-Z ]\+//g;s/[a-zA-Z]\+/\L&/g; s/ \+/\n/g' file
    

관련 정보