Дивна поведінка tr з використанням діапазонів


10

У мене є один конкретний сервер, який проявляє дивну поведінку при використанні tr. Ось приклад з працюючого сервера:

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

Це має для мене ідеальний сенс.

Однак, це з "спеціального" сервера:

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

Як бачите, видалення всіх малих символів не вдається. АЛЕ, вона видалила букву "о"

Цікава частина - це наступні два приклади, які не мають для мене сенсу:

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

(знову ж таки "o" видалено в останньому прикладі)

Хтось має уявлення, що тут відбувається? Я не можу відтворити будь-яке інше поле Linux, яке я використовую.


5
Тангенціально пов'язані: trдіапазони записуються без додавання [...]. Так tr -d '[a-z]'буде вбивати a-z, а також персонажів [і ]. Використовуйте tr -d a-zдля вбивства лише літер a-z.
Satō Katsura

Відповіді:


24

у вас є файл, названий oу поточному каталозі

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

shell буде розширювати [a-z]рядок, якщо буде знайдено збіг.

Це називається розширенням імені шляху, відповідно до man bash

Розширення Pathname
Після розбиття слів, якщо не встановлено параметр -f, bash сканує кожне слово для символів *,? Та [. ... (...)

bash виконає розширення.

[...] Збігає будь-який із вкладених символів.


@Chris Ви можете перевірити розширення оболонки, наприклад echo: touch o ; echo tr -d [a-z]дає це:tr -d o
pabouk

8

Що відбувається

Оболонка (bash) бачить аргумент [a-z]. Це шаблон підстановки ( глобус ), який відповідає будь-якій малій літери¹. Тому оболонка шукає ім'я файлу, яке відповідає цьому шаблону. Є три випадки:

  • Жоден файл у поточному каталозі не має імені, яке є однією малою літерою. Тоді оболонка залишає схему підстановки незмінною і trбачить аргументи -dі [a-z]. Це відбувається на більшості ваших машин.
  • Один файл у поточному каталозі має ім'я, яке є однією малою літерою. Потім оболонка розширює шаблон до цього імені файлу і trбачить аргументи -dта ім'я файлу. Це відбувається на сервері, і відповідний файл викликається, oоскільки ми бачимо, що trлист видалили 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:]_'видаляються малі літери та підкреслення тощо.

¹ У деяких регіонах він може відповідати іншим символам .


1
Зверніть увагу , що на Solaris 10 (і інших на основі древнього SysV Юнікси), вам потрібно tr -d '[a-z]'з /usr/bin/tr. З /usr/xpg4/bin/tr, tr -d a-zпрацює, але tr -d '[a-z]'не видаляє [ні ].
Стефан Шазелас

1
/usr/xpg4/bin/tr -d '[a-z]'не видалено [і, ]мабуть, було зафіксовано в Solaris 11.
Stéphane Chazelas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.