파이프 라인에서 여러 tr 프로세스를 피하기 위해 tr 명령을 연결할 수 있습니까?


11

나는 많은 txt 파일을 가지고 있으며, 소문자, 알파벳 및 한 줄에 한 줄씩 출력하고 싶습니다 tr. 파이프 라인에서 다음과 같은 여러 명령으로 수행 할 수 있습니다 .

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

한 번의 스캔으로이 작업을 수행 할 수 있습니까? 나는이 작업을 수행하는 C 프로그램을 작성할 수 있습니다,하지만 난 기분이 사용하여 할 수있는 방법이처럼 tr, sed, awk또는 perl.


어떤 OS를 사용하고 있습니까? GNU 도구에 액세스 할 수 있습니까?
terdon

답변:


9

로케일 종속 집합이 겹치는 복잡한 경우를 제외하고 여러 번역을 결합 할 수 있지만 삭제와 번역을 결합 할 수는 없습니다.

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

tr번의 호출은 복잡한 도구를 한 번만 호출하는 것보다 빠를 가능성이 높지만 입력 크기, 다른 문자의 비율 tr, 운영 체제, 운영 체제, 숫자에 따라 다른 문자의 비율에 따라 크게 달라집니다 코어 등


다시 확실하지 않습니다tr -s '[:upper:] [:punct:]' '[:lower:]\n' <doyle_sherlock_holmes.txt
Costas

1
@Costas 구두점을 개행 문자로 변환합니다. 이 특정 응용 프로그램에는 문제가 없지만 출력은 원본과 동일하지 않습니다.
Gilles 'SO- 악마 그만해'

@ 코스타-줄 바꿈은 여기에서 계산할 수 있지만 대문자를 짜는 것은 아닙니다. 예를 들어 , printf 'A.AAAA,A' | tr -s '[:upper:] [:punct:]' '[:lower:][\n*]'gets a\na\na', for에 대한 변환은 어쨌든 ... '[:lower:]\n'전혀 아무것도하지 않을 수도 있습니다. '[:punct:]'일부 tr는 set1을 2에 맞추기 위해 잘라 내고 일부는 묵시적으로 수행합니다 [\n*]. 범위를 사용하는 것이 좋습니다.
mikeserv

4

다음은 몇 가지 접근 방식입니다.

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

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

    grep -Po '\w+' file | perl -lne 'print lc()'
  • 펄 : 모든 알파벳 문자를 찾아 소문자로 인쇄하십시오 (@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

2
같은 것이 perl -lne 'print lc for /[[:alpha:]]+/g'작동합니까? 아니면 스타일이 좋지 않습니까? (저는 펄을
처음 접

@steeldriver 예, 그래요! Perl을 배우고 있다면 TMTOWTDI :) 감사합니다. 감사합니다. 추가하겠습니다.
terdon

3
새 버전으로 (> 4.2.1)sed -z 's/\W*\(\w\+\)\W*/\L\1\n/g'
Costas

@Costas 아, 지금 sed할 수 \w있습니까? 멋있는!
terdon

@terdon-잠시 동안 그 일이 있었지만 Costas가 언급하지 않았기 때문에 위의 의견에서 가장 흥미로운 것은 GNU sed-zero delimit 스위치 라고 생각합니다 \0NUL. 줄 바꿈보다는 s를 반복 합니다. 당신이 같은 것을 할 때 꽤 시원 tar -c . | tr -s \\0 | sed -z ...하지만 다소 느립니다.
mikeserv

4

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

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

위의 명령은 모든 대문자를 소문자로 변환하고 소문자를 완전히 무시하며 다른 모든 문자를 줄 바꿈으로 변환합니다. 물론, 당신은 빈 줄을 많이 감습니다. 이 경우 tr -squeeze repeats 스위치가 유용 할 수 있지만 [:upper:]to [:lower:]변환 과 함께 사용하면 대문자를 압착하는 것도 가능합니다. 그런 식으로 여전히 두 번째 필터가 필요합니다 ...

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

...또는...

LC... tr ... | grep .

... 그리고 그렇게하는 것보다 훨씬 덜 편리합니다.

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

... -c문자 순서대로 알파벳 문자를 하나의 줄 바꿈으로 압축 한 다음 파이프의 다른 쪽에서 위쪽에서 아래쪽으로 변환합니다.

그것은 자연의 범위가 유용하지 않다고 말하는 것은 아닙니다. 다음과 같은 것들 :

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동시에 변환 unblocklcase변환을 동시에 수행 할 수 있기 때문에 많은 작업을 전달할 수도 있습니다. 그러나 그것은 단어 당 바이트 수를 정확하게 예측할 수 있거나 적어도 unblock각 블록의 끝에 후행 공백을 먹기 때문에 적어도 예측 가능한 바이트 수까지 각 단어를 공백으로 채울 수있는 경우에만 실제로 유용 할 수 있습니다 .


점점 +2 보너스 포인트 dd관련 :
tlehman을

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