Bash 如何使用Sed取消对包含特定字符串的行的注释?

Bash 如何使用Sed取消对包含特定字符串的行的注释?,bash,awk,sed,Bash,Awk,Sed,文件中的行: -A INPUT -m state --state NEW -m tcp -p tcp --dport 2000 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 2001 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 2002 -j ACCEPT 要注释掉,让我们假设包含 2001 我可以简单地运行这个SED命令: sed -

文件中的行:

-A INPUT -m state --state NEW -m tcp -p tcp --dport 2000 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 2001 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 2002 -j ACCEPT
要注释掉,让我们假设包含

2001
我可以简单地运行这个SED命令:

sed -i '/ 2001 /s/^/#/' file
但现在我该如何恢复

就像取消注释同一行一样

我试过了

sed -i '/ 2001 /s/^//' file

那不行。

试试这个
sed
命令

sed -i '/^#.* 2001 /s/^#//' file
用更通用的,兼容POSIX的解决方案作为补充

  • 切换与可指定字符串匹配的行的注释,该字符串必须作为一个单独的单词出现在行的任何位置
  • 注释字符(字符串)也是可指定的
请注意,解决方案是基于
awk
,因为由于POSIX基本正则表达式的限制,使用
sed
的健壮的便携式解决方案实际上是不可能的

awk -v commentId='#' -v word='2001' '
  $0 ~ "(^|[[:punct:][:space:]])" word "($|[[:punct:][:space:]])" { 
    if (match($0, "^[[:space:]]*" commentId))
      $0 = substr($0, RSTART + RLENGTH)
    else
      $0 = commentId $0
  } 
  { print }
  ' file > tmpfile.$$ && mv tmpfile.$$ file
  • (^ |[:punct:[:space:])
    ($|[:punct:[:space:])
    是从其他正则表达式方言中已知的
    \
    单词边界断言的POSIX扩展正则表达式等价物
  • 保留注释字符后的空格,但不保留注释字符前的空格
  • 将注释字符前置到一行时,它直接前置,不带空格
  • 因此,如果仅使用此解决方案切换注释,则保留所有空白
  • POSIX
    awk
    不提供就地更新(顺便说一句,POSIX
    sed
    也不提供),因此首先将输出捕获到一个临时文件中,然后该文件在成功时替换原始文件

是,要用sed注释包含特定字符串的行,只需执行以下操作:

sed -i '/<pattern>/s/^/#/g' file

最后的选项“g”意味着全球变化。如果您只想更改模式的一个实例,只需跳过此操作。

对于不支持标准sed参数的mac,这将删除hashtag

sed -i "" "/.*#.*d\/docker-php-ext-xdebug\.ini.*/s/^#//g" docker-compose.yml

如何注释和取消注释文件中的行的快速示例

示例文件:

umask 027
TMOUT=600
现在,让我们备份该文件(仅供参考)并注释掉和取消注释:

# backup file (because we should always do this)
cp /etc/bash.bashrc /etc/bash.bashrc.$(date '+%Y-%m-%d,%H:%M:%S')

# original: TMOUT=600   , result :# TMOUT=600
sed -i '/[^#]/ s/\(^TMOUT=600.*$\)/#\ \1/' /etc/bash.bashrc

# original # TMOUT=600   ,result :TMOUT=600
sed -i '/^#.*TMOUT=600.*$/s/^#\ //' /etc/bash.bashrc

sed-i'/2001/s/^#/'文件可能是什么?为什么要使用这种技术?标准的技术是在脚本中使用一行,并将年数作为脚本的参数。如果没有提供参数(
${1:-2001}
),您甚至可以默认为2001,或者使用环境变量(
${default\u YEAR:-2001}
),或者两者都使用(
${1:-${default\u YEAR:-2001}
)。为什么
会删除第一个字符,即使它不是注释?仍然需要防失败。如果要选择此答案,则需要更正。您可以将匹配正则表达式的行收紧为
/^#.*2001/
,但您得到的答案严格在问题的范围内。请确保它不会失败。只有在注释后才能取消注释。哦,你是op。那么你的实际文件内容是什么呢?为macOS和BSDTo添加
-e
参数以避免多次注释,并考虑到多个前导
,请使用以下命令:
sed-i'//s//^#*//g'文件(注释掉)
sed-i'//s//^#*//g'文件(取消注释)
谢谢jnlk和@louis-m。这个解决方案对我来说是最有效的,考虑多个#字符非常有效。如果你想确保行首没有空格(例如在
#中,这是注释掉的
,你可以使用
sed-i'//s/^#*\s*//g'文件
这应该是公认的答案,解释得很好。
umask 027
TMOUT=600
# backup file (because we should always do this)
cp /etc/bash.bashrc /etc/bash.bashrc.$(date '+%Y-%m-%d,%H:%M:%S')

# original: TMOUT=600   , result :# TMOUT=600
sed -i '/[^#]/ s/\(^TMOUT=600.*$\)/#\ \1/' /etc/bash.bashrc

# original # TMOUT=600   ,result :TMOUT=600
sed -i '/^#.*TMOUT=600.*$/s/^#\ //' /etc/bash.bashrc