Как заменить определенную строку в файле на строковую переменную, используя скрипт bash с номером строки?

#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. точно, я забыл адаптировать исходный вызов к приведенному здесь примеру, но я, безусловно, доволен двумя замечаниями / исправлениями