[unix] 범위를 사용하는 tr의 이상한 동작

tr을 사용할 때 이상한 동작을 나타내는 특정 서버가 하나 있습니다. 다음은 작동중인 서버의 예입니다.

-bash-3.2$ echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
-bash-3.2$

그것은 나에게 완벽한 의미가 있습니다.

그러나 이것은 ‘특별한’서버에서 온 것입니다.

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

보다시피, 모든 소문자를 삭제하는 것은 실패합니다. 그러나 문자 ‘o’를 삭제했습니다.

흥미로운 부분은 다음 두 가지 예입니다.

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-n]
opqrstuvwxyz1234567890
[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-o]
abcdefghijklmnpqrstuvwxyz1234567890
[root@host~]#

(다시, 마지막 예에서 ‘o’는 삭제됩니다)

여기에 무슨 일이 일어나고 있는지 아는 사람이 있습니까? 사용중인 다른 Linux 상자에서는 재생할 수 없습니다.



답변

o현재 디렉토리에 이름이 지정된 파일이 있습니다

foo> ls
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
foo> touch o
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

[a-z]일치하는 것이 있으면 쉘은 문자열 을 확장 합니다.

이를 경로 이름 확장이라고합니다. man bash

경로 이름 확장
단어 분할 후 -f 옵션을 설정하지 않으면 bash는 각 단어에서 *,? 및 [문자를 검색합니다. … (…)

bash는 확장을 수행합니다.

[…] 동봉 된 문자 중 하나와 일치합니다.


답변

무슨 일이야

쉘 (bash)은 인수를 본다 [a-z]. 와일드 카드 패턴 ( glob )이며 소문자 ¹과 일치합니다. 따라서 쉘은이 패턴과 일치하는 파일 이름을 찾습니다. 세 가지 경우가 있습니다.

  • 현재 디렉토리에 파일이 하나의 소문자 인 이름이 없습니다. 그런 다음 쉘은 와일드 카드 패턴을 변경하지 않고 tr인수 -d와를 본다 [a-z]. 이것은 대부분의 컴퓨터에서 발생합니다.
  • 현재 디렉토리의 단일 파일 이름은 단일 소문자입니다. 그런 다음 쉘은 패턴을이 파일 이름으로 확장 tr하고 인수 -d와 파일 이름을 확인합니다. 이것은 서버에서 발생 하며 문자 otr삭제 되었음을 알 수 있기 때문에 일치하는 파일이 호출 됩니다 o.
  • 현재 디렉토리에있는 둘 이상의 파일 이름은 단일 소문자 인 이름을 갖습니다. 그런 다음 쉘은 패턴을 일치하는 파일 이름 목록으로 확장하고 tr세 개 이상의 인수 : -d및 파일 이름을 봅니다. 이후 tr에 단일 인수가 -d필요하므로 불평합니다.

당신이해야 할 일

명령 인수에 특수 문자가 있으면이를 이스케이프해야합니다. 작은 따옴표로 인수를 넣으십시오 '…'(이것은 가장 간단한 방법이며 다른 방법이 있습니다). 작은 따옴표 안에 작은 따옴표 자체를 제외한 모든 문자가 나타납니다. 인수 안에 작은 따옴표가 있으면으로 바꾸십시오'\'' .

tr -d '[a-z]'

그러나 이것은 아마도 당신이 의도 한 것이 아닐 수도 있습니다! tr소문자와 대괄호를 삭제하도록 지시 합니다. 그것은 동등의 tr -d ']a-z[', tr '[]a-z'소문자를 삭제하려면 등 사용

tr -d a-z

인수 tr는 문자 세트입니다. 문자 세트를 대괄호로 묶어 정규 표현식 또는 와일드 카드 패턴으로 문자 세트임을 나타냅니다. 그러나 tr한 번에 하나의 문자에서 작동합니다. 명령 줄 인수는 괄호 안에 넣습니다 .

문자 클래스 를 나타내려면 대괄호가 필요합니다 . 정규식에서 대괄호 안에 대괄호를 사용하여 문자 클래스를 나타냅니다 (예 : [[:lower:]]*소문자 [[:lower:]_]*와 일치 , 소문자와 밑줄과 일치). 의 인수에서 tr괄호없이 세트가 필요하므로 tr -d '[:lower:]'소문자를 tr -d '[:lower:]_'삭제하고 소문자와 밑줄 등을 삭제합니다.

¹ 일부 로케일에서는 다른 문자와 일치 할 수 있습니다 .


답변