tr
Посимвольная замена и удаление символов — регистр, переводы строк, лишние пробелы
tr (translate) работает с отдельными символами, а не со строками и не с регулярками: заменяет символы из одного набора соответствующими символами из другого, удаляет или сжимает повторы. Читает только стандартный ввод и пишет в стандартный вывод.
Синтаксис
tr [опции] 'набор1' 'набор2' < файл # замена
tr -d [опции] 'набор1' < файл # удаление
tr -s 'набор1' < файл # сжатие повторов
При замене первый символ набор1 превращается в первый символ набор2, второй — во второй и так далее.
Опции
| Опция | Что делает |
|---|---|
-d | удалить символы из набор1 |
-s | сжать подряд идущие одинаковые символы из последнего указанного набора в один; выполняется после замены или удаления |
-c (-C) | взять дополнение набор1 — все символы, кроме перечисленных |
-t | при замене обрезать набор1 до длины набор2 (вместо того чтобы удлинять набор2) |
Как записывать наборы
| Запись | Что значит |
|---|---|
abc | сами символы |
a-z, 0-9 | диапазон по порядку кодов |
[:lower:] [:upper:] | строчные / заглавные буквы; в паре дают смену регистра |
[:digit:] [:xdigit:] | цифры / шестнадцатеричные цифры |
[:alpha:] [:alnum:] | буквы / буквы и цифры |
[:space:] / [:blank:] | все пробельные, включая \n / только пробел и табуляция |
[:punct:] [:cntrl:] [:print:] [:graph:] | пунктуация / управляющие / печатные с пробелом / печатные без пробела |
\n \t \r \\ | перевод строки, табуляция, возврат каретки, обратный слэш |
\NNN | символ с восьмеричным кодом, например \000 — нулевой байт |
[x*] / [x*5] | во втором наборе: x столько раз, сколько нужно до длины первого / 5 раз |
Примеры
# в верхний регистр
echo 'hello' | tr 'a-z' 'A-Z'
echo 'hello' | tr '[:lower:]' '[:upper:]'
# сжать повторяющиеся пробелы в один
echo 'a b c' | tr -s ' '
# удалить все цифры / оставить только цифры
echo 'a1b2c3' | tr -d '0-9'
echo 'a1b2c3' | tr -cd '0-9'
# разделитель в перевод строки — каждое значение на своей строке
echo 'a:b:c' | tr ':' '\n'
echo "$PATH" | tr ':' '\n'
# склеить строки в одну через пробел
printf 'one\ntwo\nthree\n' | tr '\n' ' '
# убрать виндовые \r в конце строк
printf 'line\r\n' | tr -d '\r' | od -c
# заменить несколько символов разом: l → 0, o → 1
echo 'hello' | tr 'lo' '01'
# всё, что не буквы и не цифры, — в подчёркивание, повторы сжать
echo 'Hello, World! 2024' | tr -cs '[:alnum:]' '_'
# разбить текст на слова: каждое на своей строке
echo 'one two three' | tr -s '[:space:]' '\n'
# нулевые байты в переводы строк (например, /proc/*/environ)
tr '\0' '\n' < /proc/1/environ | head -n 3
# ROT13
echo 'Hello' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
Подводные камни
- Это не замена строк.
tr 'abc' 'xyz'меняетa→x,b→y,c→zпо отдельности, где бы они ни стояли. Чтобы заменить слово целиком, нужен sed. - Короткий второй набор дополняется последним символом.
echo abc | tr abc xдастxxx. С-tлишние символы первого набора просто не трогаются:echo abc | tr -t abc xдастxbc. - Файл передаётся только через
<.tr a b файл— ошибкаextra operand. - Квадратные скобки — обычные символы.
tr '[a-z]' '[A-Z]'работает лишь потому, что[переходит в[. Без кавычек[a-z]может раскрыть оболочка, если в каталоге есть файл из одной буквы. - Дефис между символами — диапазон. Чтобы заменить сам дефис, ставь его последним в наборе:
tr 'a-' 'x_'. Набор, который начинается с-и буквы ('-x'), tr примет за опцию — пишиtr -- '-x' '_y'. - Многобайтовые символы
trне понимает. GNU tr работает с байтами, поэтомуtr 'а-я' 'А-Я'портит кириллицу при любой локали. Для неё используй sed (s/.*/\U&/) или awk (toupper) в UTF-8-локали.