Я пытаюсь заменить часть path
в строке ниже из postgresql.conf с помощью сценария оболочки:
data_directory = '/var/lib/postgresql/10/main' # use data in another directory
Сначала я проверил, могу ли я сначала найти строку, используя приведенный ниже сценарий, но он не нашел строку:
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
if [[ "$line" = "data_directory = '/var/lib/postgresql/10/main' # use data in another directory" ]]
Я знаю, что есть лучший способ заменить эту строку с помощью sed
, но мне нужно знать, выполнимо ли это, прочитав файл от начала до конца, а затем заменив нужную часть строки, если она найдена. В противном случае замена всей линии только замененной частью path
тоже сделает это. Спасибо!
Мне неясно, спрашиваете ли вы: «Как мне избежать sed
» или «sed
- это нормально, но я не знаю, как это сделать». Я ответил на последнее.
Извините за путаницу @tbh, я знаю, как это сделать с помощью sed
, но я хочу сделать это с помощью цикла и всего, потому что я не знаком с ним, и я знаю, что цикл будет полезен для меня и в других сценариях. Обучение!
В строке, которую вы сравниваете с #
, перед $line
больше пробелов, чем в строке, которую вы привели в качестве примера.
REPLACEMENT_PATH=mypath
sed -i path/postgresql.conf -re "s/^(data_directory[[:space:]]*=[[:space:]]*')[^']*(')/\1${REPLACEMENT_PATH}\2/"
@tbh, спасибо, что поделились, но я хочу знать, как это сделать, прочитав файл от начала до конца, используя цикл while, как указано в вопросе. Какую ошибку вы видите в моем состоянии if
, из-за которой он не может найти линию?
Простое решение bash:
path = "/newpath"
while IFS= read -r -d $'\n'; do
if [[ "${REPLY}" == "data_directory = '/var/lib/postgresql/10/main' # use data in another directory" ]]
then echo "${REPLY/\'*\'/'${path}'}"
else echo "${REPLY}"
fi
done < postgresql.conf > new.conf
mv new.conf postgresql.conf
Контрольная работа:
$ cat postgresql.conf
# This is a comment
log_connections = yes
log_destination = 'syslog'
search_path = '"$user", public'
shared_buffers = 128MB
data_directory = '/var/lib/postgresql/10/main' # use data in another directory
# This is a comment
$ path = "/newpath"
$ while IFS= read -r -d $'\n'; do
> if [[ "${REPLY}" == "data_directory = '/var/lib/postgresql/10/main' # use data in another directory" ]]
> then echo "${REPLY/\'*\'/'${path}'}"
> else echo "${REPLY}"
> fi
> done < postgresql.conf
# This is a comment
log_connections = yes
log_destination = 'syslog'
search_path = '"$user", public'
shared_buffers = 128MB
data_directory = '/newpath' # use data in another directory
# This is a comment
Это действительно проницательно. Однако в результате я получаю data_directory = ${path}
. Не путь, назначенный переменной path
. Я буквально скопировал наклеенный. Тем не менее, +1 за проницательные подробности.
Другой подход с использованием case
- *
допускает неточный интервал между знаками равенства и перед любым комментарием, но вносит небольшую вероятность ложных совпадений. Я думаю, что с остальной конкретной информацией в строке она достаточно мала, и это не проблема.
$: cat postgresql.conf
some stuff
data_directory = '/var/lib/postgresql/10/main' # use data in another directory
some other stuff.
$: path=/new/path/to/
$: while IFS='' read -r line || [[ -n "$line" ]]
> do case "$line" in
> data_directory*=*'/var/lib/postgresql/10/main'*)
> echo "${line///*//$path}";;
> *) echo "$line";;
> esac
> done < postgresql.conf >/tmp/checkme
some stuff
data_directory = '/new/path/to/main' # use data in another directory
some other stuff.
Если хорошо, то
mv /tmp/checkme postgresql.conf
Вы можете протестировать его несколько раз, а затем просто сделать его автоматическим, но если вы не создаете постоянную автоматизацию, я бы проверил это лично.
Это сработало. Спасибо! Я добавил > postgresql.conf
в конце команды, чтобы это изменение пути было записано в файл навсегда. Но файл .conf просто стал пустым со всем содержимым. Конечно, я работал над дубликатом файла, но это был хороший урок. Не могли бы вы предложить какой-либо другой способ (используя ту же логику, что и в вашем ответе), чтобы сделать это изменение постоянным?
Это потому, что оболочка открывает (и обрезает) postgresql.conf
для записи, прежде чем когда-либо начнет читать из файла. Сначала вам нужно записать во временный файл, а затем переместить его на место после того, как вы закончите.
Обновил ответ.
Идеально!! Это не только решает проблему, но и многое объясняет новичку вроде меня.
Да, это можно сделать в обычном bash (но не рекомендуется). Используйте расширение параметра, например
${var/find/replace}
.