Почему sed не распознает t как вкладку?
sed "s/(.*)/t/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Я ожидаю, что этот скрипт sed вставит вкладку в шрифт каждой строки в $filename
однако это не так. По какой-то причине он вставляет t вместо этого.. Странный..
10 ответов:
Не все версии
sed
понять\t
. Просто вставьте литеральную вкладку вместо этого (нажмите Ctrl -V затем Tab).
С помощью Bash вы можете вставить символ табуляции программно следующим образом:
TAB=$'\t' echo 'line' | sed "s/.*/${TAB}&/g" echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
@седит был на правильном пути, но это немного неудобно, чтобы определить переменную.
решение (bash specific)
способ сделать это в bash-это использовать знак доллара перед вашей единственной строкой в кавычках.
$ echo -e '1\n2\n3' 1 2 3 $ echo -e '1\n2\n3' | sed 's/.*/\t&/g' t1 t2 t3 $ echo -e '1\n2\n3' | sed $'s/.*/\t&/g' 1 2 3
если ваша строка должна включать расширение переменной, вы можете поместить строки в кавычки вместе так:
$ timestamp=$(date +%s) $ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g' 1491237958 1 1491237958 2 1491237958 3
объяснение
в bash
$'string'
вызывает "расширение ANSI-C". И это то, что большинство нас ожидают, когда мы используем такие вещи, как\t
,\r
,\n
и т. д. От кого: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quotingслова форма $ 'string' рассматриваются специально. Слово расширяется к строка, С обратной косой чертой-экранированные символы заменяются, как указано стандарт ANSI C. Обратной косой черты escape-последовательности, если они есть, декодированный...
расширенный результат в одинарных кавычках, как если бы знак доллара не имел присутствовал.
решение (если вы должны избегать bash)
я лично думаю, что большинство попыток избежать bash глупы, потому что избегание башизмов не делает ваш код переносимым. (Ваш код будет менее хрупким, если вы shebang его в
bash -eu
чем если вы пытаетесь избежать bash и использоватьsh
[если вы не абсолютный POSIX ниндзя].) Но вместо того, чтобы иметь Религиозный аргумент об этом, Я просто дам вам лучший * ответ.$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g" 1 2 3
* лучший ответ? Да, потому что одним из примеров того, что большинство скриптеров оболочки anti-bash будут делать неправильно в своем коде, является use
echo '\t'
а в @robrecord это. Это будет работать для GNU echo, но не для BSD echo. Это объясняется открытой группой в http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 и это пример того, почему попытки избежать башизмов обычно терпят неудачу.
я использовал что-то вроде этого с оболочкой Bash на Ubuntu 12.04 (LTS):
добавить новую строку с tab, второй, когда первый сочетается:
sed -i '/first/a \t second' filename
заменить первый С tab, второй:
sed -i 's/first/\t second/g' filename
использовать
$(echo '\t')
. Вам понадобятся кавычки вокруг шаблона.например. Чтобы удалить вкладку:
sed "s/$(echo '\t')//"
вам не нужно использовать
sed
чтобы сделать замену, когда на самом деле, вы просто хотите вставить вкладку перед строкой. Замена для этого случая является дорогостоящей операцией по сравнению с просто распечаткой, особенно когда вы работаете с большими файлами. Его легче читать, а не регулярное выражение.например, с помощью awk
awk '{print "\t"}' $filename > temp && mv temp $filename
sed
не поддерживает\t
, ни другие escape-последовательности, такие как\n
если уж на то пошло. Единственный способ, который я нашел, чтобы сделать это было на самом деле вставить символ вкладки в скрипт с помощьюsed
.тем не менее, вы можете рассмотреть возможность использования Perl или Python. Вот короткий скрипт Python, который я написал, который я использую для всех потоков regex'ING:
#!/usr/bin/env python import sys import re def main(args): if len(args) < 2: print >> sys.stderr, 'Usage: <search-pattern> <replace-expr>' raise SystemExit p = re.compile(args[0], re.MULTILINE | re.DOTALL) s = sys.stdin.read() print p.sub(args[1], s), if __name__ == '__main__': main(sys.argv[1:])
вместо BSD sed я использую perl:
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g" hi
Я думаю, что другие разъяснили это адекватно для других подходов (
sed
,AWK
и т. д.). Однако, мойbash
-конкретные ответы (протестированы на macOS High Sierra и CentOS 6/7) следуют.1) Если OP хотел использовать метод поиска и замены, аналогичный тому, что они первоначально предложили, то я бы предложил использовать
perl
для этого, как следует. Примечания: обратные косые черты перед скобками для регулярного выражения не должны быть необходимы, и эта строка кода отражает, каклучше использовать, чем
С
perl
оператор подстановки (например, per Perl 5 документация).perl -pe 's/(.*)/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) однако, как указал ghostdog74, так как желаемая операция на самом деле просто добавить вкладку в начале каждой строки перед изменением файла tmp на ввод/целевой файл (
$filename
), Я бы порекомендовалperl
снова, но со следующими изменениями(ы):perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename ## OR perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
3) Конечно, tmp файл лишние, так что лучше просто сделать все "на месте" (добавление
-i
флаг) и упростить вещи к более элегантному ОДН-вкладышу сperl -i -pe $'s/^/\t/' $filename