【问题标题】:Need to replace a specific part of line from a file using shell script需要使用 shell 脚本从文件中替换行的特定部分
【发布时间】:2018-12-17 12:14:47
【问题描述】:

我正在尝试使用 shell 脚本从 postgresql.conf 替换以下行的 path 部分:

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 部分替换整行也可以。谢谢!

【问题讨论】:

  • 是的,它在普通 bash 中是可行的(但不推荐)。使用参数扩展,例如${var/find/replace}
  • 我不清楚您是在问,“我怎样才能避免sed”或“sed 可以,但我不知道如何。”我已经回答了后者。
  • 对不起@tbh 的困惑,我知道sed 怎么做,但我想用循环来做这一切,因为我不熟悉它,我知道循环会很有用在其他情况下对我来说也是如此。学习!
  • 您与$line 比较的字符串中# 之前的空格比您作为示例给出的行多。

标签: bash shell ubuntu


【解决方案1】:

简单的 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 以获得有见地的细节。
【解决方案2】:

使用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

您可以对其进行几次测试,然后使其自动化,但除非您正在构建一个持续的自动化,否则我会亲自检查。

【讨论】:

  • 这行得通。谢谢!我在命令末尾添加了&gt; postgresql.conf,以将此路径更改永久写入文件。但是 .conf 文件只是变空了,所有内容都消失了。当然,这是我正在处理的重复文件,但这是一个很好的教训。您是否会建议任何其他方式(使用与您的答案相同的逻辑)来使此更改永久化?
  • 这是因为 shell 在开始读取文件之前打开(并截断)postgresql.conf 进行写入。您需要先写入一个临时文件,然后在完成后将其移动到位。
  • 更新了答案。
  • 完美!!这不仅解决了问题,而且给像我这样的新手解释了很多东西。
【解决方案3】:
REPLACEMENT_PATH=mypath
sed -i path/postgresql.conf -re "s/^(data_directory[[:space:]]*=[[:space:]]*')[^']*(')/\1${REPLACEMENT_PATH}\2/"

【讨论】:

  • @tbh,感谢您的分享,但我想知道如何通过使用问题中提到的 while 循环从头到尾读取文件来做到这一点。你在我的if 条件中看到了什么错误,导致它找不到行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 2018-07-08
相关资源
最近更新 更多