#linux #bash #sed
#linux #bash #sed
Вопрос:
Вот содержимое target.txt файл:
line1
line2
Environment=xLink=https://11111/route
line4
line5
Я пытаюсь написать скрипт bash, который найдет номер строки, содержащей «https», а затем заменит всю эту строку новой строковой переменной, полученной в скрипте bash, вот скрипт bash без строки замены:
#!/bin/bash
x="12345"
route="/route"
x_route="${x}${route}"
x_init="Environment=xLink=https://"
new_line="${x_init}${x_route}"
echo "${new_line}"
to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1-2)
echo "${to_replace_line_number}"
targetfile=target.txt
echo "${targetfile}"
Вызов этого скрипта выдает следующее, как и ожидалось:
Environment=xLink=https://12345/route
3:
target.txt
Теперь, без скрипта bash, если я вызвал:
sudo sed -i '3 cEnvironment=xLink=https://12345/route' target.txt
The target.txt изменения по желанию в:
line1
line2
Environment=xLink=https://12345/route
line4
line5
Но цель состоит в том, чтобы автоматизировать, поэтому я пытаюсь использовать команду sed для выполнения работы внутри скрипта bash. До сих пор я пробовал два метода, ни один из них не работал.
Способ 1: я добавил следующую строку в скрипт bash:
sudo sed -i "${to_replace_line_number}s/.*/${new_line}/" ${targetfile}
Когда я запустил скрипт, он не сработал, и я получил эту ошибку:
sed: -e expression #1, char 2: : doesn't want any addresses
Способ 2:
Я добавил следующую команду в скрипт bash:
sudo sed -i "${to_replace_line_number} c${new_line}" ${targetfile}
Когда я запустил скрипт, он не сработал, и я получил эту ошибку:
sed: -e expression #1, char 2: : doesn't want any addresses
Чего именно мне не хватает? Любая помощь очень ценится.
Комментарии:
1. предполагая
${to_replace_line_number}
, что ==3:
, вашsed
становится:sed -i "3: c...
; это, по-видимому, соответствует сообщению об ошибке оchar 2
==:
; зачем прыгать через обручи поиска номера строки, когдаsed
можно найти и заменить строку, содержащуюhttps
без необходимости каких-либо номеров строк?2. О да, я пробовал это, и я не могу заставить это работать. Я уже пытаюсь заставить sed выполнить определенную вещь, то есть заменить строку номер 3 строковой переменной. Очевидно, что я не готов или не способен вызвать одну команду sed в скрипте bash, которая найдет строку и заменит ее, не могли бы вы поделиться своим подходом или строкой кода или чем-то еще?
Ответ №1:
Это потому, что вы удаляете два символа при чтении номера строки.В результате в переменной появляется лишнее ‘:’. Вместо этого удалите только одно поле, и оно должно работать нормально.
Заменить
to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1-2)
с помощью
to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1)
Комментарии:
1. это работает до тех пор, пока соответствует номер строки
< 10
; вероятно, лучше использоватьcut -d":" -f1
, поскольку это даст нам полный номер строки независимо от того, сколько цифр (1, 2, 5, …)
Ответ №2:
это специальный символ, поэтому, когда вы используете его в двойных кавычках, вы должны экранировать его:
# Set example values and create a test file:
to_replace_line_number="3"
new_line="Environment=xLink=https://12345/route"
targetfile="test.txt"
printf 'line%dn' {1..5} > "$targetfile"
# The actual command
sudo sed -i "${to_replace_line_number} c\${new_line}" "${targetfile}"
Это сделало бы его эквивалентным вашему вызову вручную.
Если вы задавались вопросом, почему документация для c
выглядит странно отформатированной по сравнению с r
или y
, это потому, что перевод строки после
является преднамеренным. Это способ POSIX сделать это:
sudo sed -i "${to_replace_line_number} c\
${new_line}" "${targetfile}"
Ответ №3:
Есть пара проблем с текущим кодом:
to_replace_line_number
==3:
— ОБРАТИТЕ ВНИМАНИЕ на двоеточие (:
); это вводится вsed
команду следующим образом:sed -i "3: c....
и генерирует сообщение об ошибке, в котором указывается проблема со 2-м символом, т. Е.:
- как указал @thatotherguy в своем ответе, для этого
c
параметра требуется escape-символ и встроенный возврат каретки … или …
Минимальные изменения в текущем коде OPs:
# parse the `grep -n` by having `cut` pull everthing before the (first) `:`
$ to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -d":" -f1)
$ echo "${to_replace_line_number}"
3
# modification to @thatotherguy's `sed/c` suggestion to allow all code to go on a single line:
$ sed -i -e "${to_replace_line_number} c\" -e "${new_line}" ${targetfile}
$ cat "${targetfile}"
line1
line2
Environment=xLink=https://12345/route
line4
line5
Вместо того чтобы вызывать вызовы подпроцесса для получения номера строки, sed
можно использовать несколько способов поиска и замены нужной строки.
Одна sed
идея:
sed -i "s|^.*https.*$|${new_line}|" ${targetfile}
Где:
|
— используйте канал в качествеsed
разделителя, поскольку${new_line}
содержит косые черты^.*https.*$
— сопоставьте любую строку, содержащую строкуhttps
${new_line}
— замените строку содержимым${new_line}
После выполнения приведенного выше:
$ cat target.txt
line1
line2
Environment=xLink=https://12345/route
line4
line5
Комментарии:
1. точно, я забыл адаптировать исходный вызов к приведенному здесь примеру, но я, безусловно, доволен двумя замечаниями / исправлениями