【问题标题】:How to add a carriage return with sed?如何用sed添加回车?
【发布时间】:2018-03-23 13:16:03
【问题描述】:

我正在尝试使用 sed 将 pgbouncer.ini 中的 [databases] 替换为

[databases]
db = host=localhost port=5432 dbname=db user=r00t password=xyz

这是我的 bash 脚本:

CR=$(printf '\r')
sed "s/\[databases\]\$/\[databases\]$CR db = host=localhost port=5432 dbname=db user=r00t password=xyz/" pg.ini

不幸的是,我只看到了这个:

db = host=localhost port=5432 dbname=db user=r00t password=xyz

更新:

变量会导致接受的答案出现问题。我得到错误:

sed: -e 表达式 #1, char 127: 命令后的多余字符

sed -i "/\[databases\]/a\
main_db = host=${MAIN_DB_LOC} port=5432 dbname=${MAIN_DB} user=r00t password=${MAIN_DB_PASSWORD}
audit_db = host=${AUDIT_DB_LOC} port=5432 dbname=${AUDIT_DB} user=r00t password=${AUDIT_DB_PASSWORD}
lat_lng_db = host=${LAT_LNG_DB_LOC} port=5432 dbname=${LAT_LNG_DB} user=r00t password=${AUDIT_DB_PASSWORD}
" /etc/pgbouncer/pgbouncer.ini

【问题讨论】:

  • 我猜你想要CR=$(printf '\r\n') (Windows) 或CR=$(printf '\n') (UNIX)

标签: bash ubuntu sed


【解决方案1】:

使用换行符代替CR,在sed 中以\n 的形式提供(Unix 上的LF):

$ sed 's/\[databases\]$/&\ndb = host=localhost port=5432 dbname=db user=r00t password=xyz/' pg.ini

另外,行尾锚$ 不需要转义(如果在单引号下使用),您可以使用& 在您的替换字符串。


要使用port 变量:

$ port=5432
$ sed 's/\[databases\]$/&\ndb = host=localhost port='"$port"' dbname=db user=r00t password=xyz/' pg.ini

(注意我们需要使用双引号来扩展$port,这就是我们连接单引号和双引号sed子字符串的原因,例如'x'"y"'z'。)

【讨论】:

  • 如果端口是一个变量而不是硬编码,这是一个很好的解决方案。我实际上可能会接受这个作为答案。
  • 是的,确实,我认为这仍然是一个很好的解决方案,可以将所有内容放在一条线上。修改后的接受答案的一个优点是保持每一行分开以便于阅读。谢谢
【解决方案2】:

您可以像这样使用a append 命令:

sed -i '/\[databases\]/a\
db = host=localhost port=5432 dbname=db user=r00t password=xyz
' file

以下是如何将端口用作变量:

port='5432'

sed -i '/\[databases\]/a\
db = host=localhost port='"$port"' dbname=db user=r00t password=xyz
' file

或者如果有问题中所示的一长串变量,您可以使用这个sed

sed -i "/\\[databases\\]/a\\
main_db = host=${MAIN_DB_LOC} port=5432 dbname=${MAIN_DB} user=r00t password=${MAIN_DB_PASSWORD}\\
audit_db = host=${AUDIT_DB_LOC} port=5432 dbname=${AUDIT_DB} user=r00t password=${AUDIT_DB_PASSWORD}\\
lat_lng_db = host=${LAT_LNG_DB_LOC} port=5432 dbname=${LAT_LNG_DB} user=r00t password=${AUDIT_DB_PASSWORD}\\
" file

由于sed 命令中存在双引号,请注意使用\\ 而不是\


或者,您可以使用sedr 命令将文件的内容放在输出中。

# create a temporary file with the text to be placed after [databases]
echo 'db = host=localhost port=5432 dbname=db user=r00t password=xyz' > file.tmp

# Copy the contents of file to the standard output after search string
sed -i.bak '/\[databases\]/r file.tmp' file

【讨论】:

  • 不幸的是,如果端口必须是变量而不是硬编码,则此解决方案将不再有效。如果你使用 " " 而不是 ' ',sed 会抛出一个错误。
  • 以使用变量的示例更新答案
【解决方案3】:

sed 用于单独行上的简单替换,仅此而已。对于其他任何你应该使用 awk 的东西:

awk '{print} $0=="[databases]"{print "db = host=localhost port=5432 dbname=db user=r00t password=xyz"}' file

以上内容适用于任何 UNIX 系统上的任何 shell 中的任何 awk,并且当您的目标字符串包含正则表达式元字符或分隔符时不会失败(例如,/ 是 sed 中的默认值),也不会在您的附加字符串包含反向引用时失败(例如&\1)。那是因为它使用了 sed 不支持的严格的字符串操作。

【讨论】:

  • sed 不仅仅可以用于简单的替换!更重要的是,如果您需要在 sed 中使用元字符,您只需引用它们,就像您需要引用任何 "` characters in your awk example; or you can use a sed command like a` 一样,这是一个“字符串操作”你的 awk 例子。
  • 可以,但不应该。当您这样做时,您使用的是在 1970 年代中期 awk 被发明时已经过时的构造,结果是复杂、低效且通常不可移植。当您说“引号”时,您的意思是“转义”,这样做既麻烦又不重要(请参阅stackoverflow.com/a/29626460/1745001),并且当您可以只使用支持字符串的工具而不是破解您的正则表达式来尝试时,通常毫无意义阻止 sed 如此对待它。今天使用 sed 超过s/old/new/ 只是为了心理锻炼。
  • 字符引用是转义的particular case;在这种情况下两者都是正确的,“引用”只是稍微具体一点。是的,我不会推荐任何人应该在 sed 中编写大型程序——那太疯狂了! - 但是说“这就是所有”它可以做的是误导,因为它给人的印象是你可以用它做的所有事情,而不是你应该用它做的所有事情.而且,无论您使用的是 sed、awk、SQL 还是其他任何东西,您都必须始终小心引用...
  • 我没有说这就是它所能做的,我说这就是它的全部。你可以用茶匙挖沟,但这不是茶匙的用途。必须在文字字符串中引用字符串分隔符与必须为每个上下文以适当的方式转义每个正则表达式和反向引用元字符或字符串之间存在巨大差异。向我展示任何不仅仅是 s/old/new 的 sed 脚本,我将向您展示一种更好的方法,“更好”是任何/所有清晰度、性能、可移植性、内存等。如果您对此表示怀疑,发布问题...
  • 是的,你说这就是它的全部“为了”,暗示这是作者的意图,这可能会让读者相信他们没有添加任何功能来做任何其他事情- 不幸的是,事实并非如此。说出类似“sed 仅推荐用于(简单的东西)”或“不建议将 sed 用于...”的内容会使您的意图更加清晰。正如我所说的,我不建议人们在 sed 中编写复杂的东西,没有争论!
猜你喜欢
  • 2016-10-17
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多