【问题标题】:sed replace fails to replace string in if there's a square bracket如果有方括号,sed replace 无法替换字符串
【发布时间】:2019-03-14 02:53:41
【问题描述】:

我的结果变量包含以下内容:

auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=888
auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=888

我想替换整行,我正在使用 sed。替换似乎在第一次迭代时可以正常工作,但在第二次迭代中不行。但是,当我打印这些值时,它表明新值已正确更新。

echo "$result" |
   while IFS= read -r line;
   do
      newValue=""
      for ii in $line
      do
         if [[ "$ii" != *"unlock_time"* ]]; then
            newValue="$newValue $ii"
         fi
      done
      newValue="$newValue unlock_time=900"
      sed -i "s/$line/$newValue/g" $password_auth
      echo " Line    : [ $line ]"
      echo "newValue : [ $newValue ]"
   done

输出显示如下:

 Line    : [  auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=900 ]
newValue : [  auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=900 ]
 Line    : [ auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=888 ]
newValue : [  auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=900 ]

在这里显示时,我看到变量中存在正确的值,并且所有打印都发生在 sed 命令之后,并且在输出打印之前我没有看到任何错误。

但是当我检查文件时,我看到 unlock_time 的第二个实例仍然是 888 而不是 900。

注意:我无法全局替换 unlock_time,这就是我将需要更新的行存储在结果中的原因。

循环中有什么被忽略的吗?

更新: 我试过在命令行上运行 sed 命令:

sed -i "s/auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=900/auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=999/g" temp  <-- This works
sed -i "s/auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=9/auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=900/g" temp   <-- This doesn't update file but doesn't throw an error either

当我将转义字符放在 [default=die] 周围时,该命令在命令行上起作用。但是如果我是通过脚本来做的,我该怎么做呢?

【问题讨论】:

  • 如果您想在替换命令的 LHS 中匹配 [],则必须引用它们,即 [ 必须更改为 \[[[],以便 @ 987654331@ 不被视为bracket expression 的元字符。
  • 是的,但在我的情况下,我正在从文件中读取值,所以我不会事先知道是否有括号。
  • 你是用 bash 做这个吗?
  • 是的,我正在通过 bash 脚本进行操作...
  • 如果你想在变量中引用 [] 字符,使用 sed 创建一个新变量,例如newvar=$(&lt;&lt;&lt;"$oldvar" sed 's/[].*[]/\\&amp;/g')

标签: sed


【解决方案1】:

您正试图找到一个常数。通过引用层匹配的正则表达式正在阻碍。这是一个更简单的 perl 方法(出于演示目的,包装在 bash 中):

#!/bin/bash

result="auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=888 unlock_time=888
auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=888 unlock_time=888"

# create a file to play with
echo "$result" > testfile

echo "$result" | perl -i -pe '
    BEGIN { @find = <STDIN> }
    for $str (@find) {
        s/(\bunlock_time)=\d+/$1=900/ if $_ eq $str;
    }
' testfile

# check the result
cat testfile
  • -i 确实像 sed 一样就地编辑
  • -p 包装了一个 while 循环来读取每一行,因此不需要显式的循环,并在可能的修改后打印出该行(有点像 sed)
  • BEGIN 部分初始化要查找的字符串数组(来自结果)
  • 对于测试文件的每一行 ($_),for 将其与所有字符串进行比较,if 存在文字匹配 (eq),对 unlock_time 参数进行正则表达式搜索和替换

【讨论】:

  • 谢谢。我试过运行那个脚本... 结果变量:auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=990 unlock_time=900 auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=990 输出: auth required pam_faillock.so preauth silent audit deny=3 even_deny_root fail_interval=990 unlock_time=900 auth [default=die] pam_faillock.so authfail audit deny=3 even_deny_root fail_interval=990 输出与输入相同...
  • 为什么不呢?如果输入 900 并将其更改为 900,则输出将为 900
猜你喜欢
  • 2015-02-26
  • 2020-06-12
  • 1970-01-01
  • 2013-01-04
  • 2018-10-18
  • 1970-01-01
  • 2013-08-14
  • 1970-01-01
  • 2018-12-26
相关资源
最近更新 更多