Я хотел бы заменить набор символов соответствующими символами из другого набора, примерно так:
original set: ots
"target" set: u.x
foobartest → fuubar.ex.
Подобные переводы / транслитерации являются специальностью tr
команды:
$ echo 'foobartest' | tr 'ots' 'u.x'
fuubar.ex.
К сожалению tr
, не поддерживает изменение файлов на месте, как это sed
делает.
Я хотел бы использовать, sed
чтобы мне не пришлось заново изобретать колесо жонглирования временными файлами.
tr
(правильно) игнорирует рекурсию в наборах замены:echo 'abc' | tr ab bx
→bxc
. Примитивное решение может привести к этому,xxc
потому что оно повторно применяет перевод к уже переведенным символам.sed
отличие от GNUtr
может транслитерировать многобайтовые символы)Ответы:
sed
имеетy
команду, которая работает так же, какtr
:Команда
y
является частью спецификации POSIXsed
, поэтому она должна работать практически на любой платформе.И поскольку это так
sed
, вы можете заменить файл на его отредактированную версию, избавив вас от хлопотного бизнеса временных файлов (если ваша реализацияsed
поддерживает-i
опцию, которая не указана в POSIX):источник
sed
's', не означает, что другие функции также хороши . ;) В списке рассылки Vim есть ветка о поискеy/abc/def/
эквивалента; лучший вариант, кажется:%call setline(".", tr(getline("."),"abc","def"))
.Если, как и в вашем случае, вы транслитерируете символы без изменения их размера (в любом случае, некоторые реализации, такие как GNU,
tr
поддерживают только однобайтовые символы), вы можете сделать:То есть
tr
перезаписать файл поверх себя.Это лучше, чем
sed -i
на нескольких счетах:Один из недостатков заключается в том, что если он прерван, файл в итоге будет переведен наполовину (однако в этом случае вы можете запустить его снова, чтобы завершить его). Некоторые
sed
реализации справились бы с этим правильно, убедившись, что исходный файл остается неизменным, пока команда не будет выполнена успешно.источник
echo 'abc' | tr ab bx
.tr
а в нашей среде PXE, насыщенной символическими ссылками, это было запутаннымsed -i
ожиданием случиться…: /iconv -t cp437
кажется более подходящим для этого.iconv
прерывается, когда входной файл уже содержит байты в кодировке cp437 или смесь нескольких кодировок. Поэтому, хотя в общем случае это предпочтительнее, в этом случае более надежно выполнять замену вручную.В качестве другой альтернативы, если вашей основной проблемой является отсутствие поддержки для изменения файлов на месте, вас может заинтересовать
sponge
инструмент из пакета moreutils :будет записывать
file
, но открыватьfile
для записи только после завершения ввода. Из справочной страницы :Если у вас нет действительно больших файлов, которые не могут быть сохранены в памяти, они
sponge
могут работать на вас.источник
sponge
заключается в том, что он все равно перезаписывается вfile
случаеtr
сбоя (например, если у вас был доступ для записи, но вы не читалиfile
)cat file >; file
оператор ksh93, который записывает вывод в временный файл, который переименовывается в место назначения, только если команда выполнена успешно (но, напримерsed -i
, это создает новый файл вместо перезаписи оригинала).