Если вы хотите заменить ключевое слово на строку с помощью sed, sed старается интерпретировать заменяемую строку. Если в строке замены есть символы, которые sed считает специальными, например, символ '/', то произойдет сбой, если, конечно, вы не предполагали, что в строке замены есть символы, которые говорят sed, как действовать.
Пример:
VAR="hi/"
sed "s/KEYWORD/$VAR/g" somefile
Есть ли способ сказать sed не пытаться интерпретировать строку замены для специальных символов? Все, что я хочу - это иметь возможность заменить ключевое слово в файле содержимым переменной, независимо от того, что это за содержимое.
bash
shell-script
sed
Tal
источник
источник
sed
них и не использовать их, просто удалите их с обратной косой черты.VAR='hi\/'
не дает такой проблемы.sed(1)
просто интерпретирует, что он получает. В вашем случае он получает это через интерполяцию оболочки. Я считаю, что вы не можете делать, как хотите, но проверьте руководство. Я знаю, что в Perl (который делает проходимуюsed
замену с гораздо более богатыми регулярными выражениями), вы можете указать строку, которую нужно воспринимать буквально, опять же, проверьте руководство.Ответы:
Есть только 4 специальных символов в сменной части: \, &, перевод строки и разделитель ( ссылка )
источник
s///
является не регулярным выражением, это действительно просто строка (для обратных косых черт побегов и , кроме&
). Если строка замены слишком длинная, однострочная оболочка не является вашим решением.Вы можете использовать Perl вместо sed с помощью
-p
(предположите, что цикл за вводом) и-e
(укажите программу в командной строке). С Perl вы можете обращаться к переменным окружения, не интерполируя их в оболочке. Обратите внимание, что переменная должна быть экспортирована :Если вы не хотите экспортировать переменную везде, просто предоставьте ее только для этого процесса:
Обратите внимание, что синтаксис регулярного выражения в Perl по умолчанию немного отличается от синтаксиса sed.
источник
PATTERN
переменная окружения , а не аргументы. В любом случае, эта ошибка будетE2BIG
, которую вы бы в равной степени получили, если бы использовалиsed
.Самое простое решение, которое по-прежнему будет правильно обрабатывать подавляющее большинство значений переменных, заключается в использовании непечатаемого символа в качестве разделителя для
sed
команды замены.В
vi
вы можете избежать любого символа управления, набрав Ctrl-V (чаще записываются в виде^V
). Поэтому, если вы используете какой-либо управляющий символ (я часто использую^A
в качестве разделителя в этих случаях), вашаsed
команда будет прерываться, только если этот непечатаемый символ присутствует в переменной, в которую вы добавляете.Таким образом, вы напечатаете,
"s^V^AKEYWORD^V^A$VAR^V^Ag"
и то, что вы получите (вvi
), будет выглядеть так:Это будет работать до тех пор, пока
$VAR
не будет содержать^A
непечатный символ, что крайне маловероятно.Конечно, если вы передаете пользовательский ввод в значение
$VAR
, тогда все ставки отключены, и вам лучше тщательно санировать свой ввод, чем полагаться на то, что контрольные символы сложно набрать для обычного пользователя.Однако на самом деле нужно знать больше, чем строка-разделитель. Например,
&
когда присутствует в строке замены, означает «весь текст, который был сопоставлен». Например,s/stu../my&/
заменил бы «stuff» на «mystuff», «stung» на «mystung» и т. Д. Итак, если у вас есть какой-либо символ в переменной, который вы добавляете в качестве строки замены, но вы хотите использовать литерал только значение переменной, тогда у вас есть некоторая очистка данных, прежде чем вы сможете использовать переменную в качестве строки замены вsed
. (Однако очистка данных может быть выполненаsed
также.)источник
sed
«ыi
командной nsert. Ноsed
это не хороший инструмент для обработки большого количества текста сложными способами. Я выложу другой ответ, показывающий, как это сделатьawk
.Вместо этого вы можете использовать a
,
или a,|
и он будет восприниматься как разделитель, а технически вы можете использовать что угодносо страницы руководства
Как вы можете видеть, вы должны начинать с \ перед вашим разделителем в начале, тогда вы можете использовать его как разделитель.
из документации http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command :
Пример:
sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"
echo "Hello/ World" | sed "s,Hello/,Neo,"
источник
/
и он будет игнорировать/
счастливо, как я только что указал .. на самом деле, вы даже можете найти его и заменить его в строке >>> я редактировал с примером >>> эти вещи не так безопасны, и вы всегда найдете умнее, чувакsed
во-первых, для чего нужен ваш проект?bash
это НЕ для работы со строками. На всех, на всех, на всех. Это для манипулирования файлами и координации команд . Это имеет некоторую встроенную удобную функциональность для строк, но на самом деле ограниченную и не очень быструю, если это главное, что вы делаете. Смотрите "Почему использование цикла оболочки для обработки текста считается плохой практикой?" Некоторые инструменты, которые предназначены для обработки текста, в порядке от самых простых до самых мощных:sed
,awk
и Perl.Если он основан на строках и заменяется только одной строкой, я рекомендую добавить сам файл с помощью строки замены
printf
, сохраняя эту первую строку в местеsed
для хранения, и добавляя ее при необходимости. Таким образом, вам не нужно беспокоиться о специальных символах. (Единственное допущение здесь состоит в том, что он$VAR
содержит одну строку текста без каких-либо символов новой строки, о чем вы уже говорили в комментариях.) Кроме строк новой строки, VAR может содержать все что угодно, и это будет работать независимо.printf '%s\n'
будет печатать содержимое$VAR
в виде буквенной строки, независимо от ее содержимого, за которой следует новая строка. (echo
в некоторых случаях будет выполнять другие действия, например, если содержимое$VAR
начинается с дефиса - это будет интерпретироваться как передаваемый флаг опцииecho
.)Скобки используются для добавления вывода
printf
к содержимому того,somefile
как оно передаетсяsed
. Здесь важны пробелы, разделяющие фигурные скобки, и точка с запятой перед закрывающей фигурной скобкой.1{h;d;};
какsed
команда будет хранить первую строку текста вsed
«S трюма , затемd
далить линию (а не печать)./KEYWORD/
применяет следующие действия ко всем строкам, которые содержатKEYWORD
. Действие - этоg
et, которое получает содержимое пространства удержания и удаляет его вместо пространства шаблона - другими словами, всей текущей строки. (Это не для замены только части строки.) Между прочим, пространство удержания не освобождается, а просто копируется в пространство шаблона, заменяя все, что там есть.Если вы хотите привязать свое регулярное выражение, чтобы оно не совпадало со строкой, которая просто содержит KEYWORD, а содержит только строку, в которой нет ничего другого, кроме KEYWORD, добавьте начало строки anchor (
^
) и конец строки anchor ($
) в Ваше регулярное выражение:источник
Вы можете использовать обратную косую черту в прямой строке замены, используя расширение параметра подстановки шаблона Bash. Это немного грязно, потому что косые черты также нужно избегать для Bash.
вывод
Вы можете поместить расширение параметра непосредственно в вашу команду sed:
но я думаю, что первая форма немного более читабельна. И, конечно, если вы собираетесь повторно использовать один и тот же шаблон замены в нескольких командах sed, имеет смысл просто выполнить преобразование один раз.
Другим вариантом будет использование сценария, написанного на awk, perl или Python, или C-программы, для выполнения замен вместо использования sed.
Вот простой пример в Python, который работает, если заменяемое ключевое слово является полной строкой во входном файле (не считая перевода строки). Как видите, это по сути тот же алгоритм, что и в вашем примере с Bash, но он читает входной файл более эффективно.
источник
\x
escape-последовательности в стиле. Или использовать программу, которая может обрабатывать произвольный ввод, как я упоминал в моем предыдущем абзаце.Это путь, которым я пошел:
это прекрасно работает в моем случае, потому что мое ключевое слово в строке само по себе. Если ключевое слово находится в строке с другим текстом, это не будет работать.
Я все еще хотел бы знать, есть ли простой способ сделать это, не включающий в себя кодирование моего собственного решения.
источник
echo
вообще. Используйтеprintf
вместо этого. И обработка текста в цикле оболочки - плохая идея.read
довольно медленно. Он предназначен для обработки интерактивного пользовательского ввода, а не для обработки текстовых файлов. Это медленно, потому что он читает stdin char за char, делая системный вызов для каждого char.printf "hi\n"
заставит printf печатать новую строку, покаecho "hi\n"
печатает как есть.printf
означает «формат» - первый аргумент дляprintf
- это спецификатор формата . Если спецификатор%s\n
, что означает «строка с последующим переводом строки», ничего в следующем аргументе не будет интерпретироваться или переведеныprintf
на все . (Разумеется, оболочка все еще может его интерпретировать; лучше всего указывать все в одинарных кавычках, если это буквальная строка, или в двойных кавычках, если вы хотите раскрыть переменную.) Более подробные сведения см. В моем ответеprintf
.