【问题标题】:Bash: remove double slashes (uncomment line)Bash:删除双斜杠(取消注释行)
【发布时间】:2015-04-23 01:02:06
【问题描述】:

我想删除行首的双斜杠以取消注释一行代码,例如第一个注释。我的方法适用于许多其他情况,但这次还不够。这是我的文件 .sh 中的一段代码:

while read line
    do
        if [[ $line == *"#define asdasd"* ]]
        then
            local prefix="\\/\\/ "
            local new=${line#$prefix}
            local sub="s/$line/$new/g"
            echo "old line: " $line
            echo "new line: " $new
            echo $sub
            perl -pi -e "$sub" $FILE
            exit
           fi
    done < $FILE

编辑:

我的问题比这段代码更复杂。我只想取消注释(删除双斜杠)与模式匹配的一行,而不一定是第一行。这就是为什么我不能对整个文件进行操作,而是逐行操作的原因。所以所有的“perl on match”解决方案都不适用于我的情况。

编辑:

我正在按照一些用户的建议编辑我的问题。

  • 背景:我正在使用嵌入式(复杂)操作系统,我无法为自己的目的修改每个文件(即makefile)。
  • 目的:我想多次构建代码,每次都启用不同的标志。

在我当前的解决方案中,我将所有标志收集在一个头文件中,并且在每次构建时只启用一个。这是我的 .h 文件的示例:

#ifndef SYSTEM_H
#define SYSTEM_H

#include <...>

#define BLA       1
#define BLABLA    2
#define BLABLABLA 3

// #define OPT_0 // Options disabled
// #define OPT_1
#define OPT_2 // Option enabled
// #define OPT_...
// #define OPT_...
// #define OPT_N

[...]

#define function(__exp) \
  [...]

#endif

如您所见,我不知道我必须启用/禁用多少选项,还有其他#define 说明。

我正在编写一个脚本,它一次启用一个标志并构建项目。每次编译的文件都被重命名以防止覆盖。我的一个解决方案是基于上面列出的代码,但不幸的是 perl 指令不会修改 .h 文件,删除所选行开头的双斜杠。

【问题讨论】:

  • 如果您粘贴到 shellcheck.net 中,您会看到一个错误:“确保不要在同一管道中读取和写入同一文件。”。也就是说,您正在循环一个文件并同时对其进行编辑。另外,在我看来,您选择了一种长方法:对文件执行perl -pi 而不循环遍历它不是更好吗?
  • 我的问题要复杂得多。所以相信我,我必须通读我的文件并检查每一行。
  • 好的,那么你必须考虑到你不能改变你正在阅读的内容,因为行为是不可预测的。
  • 您的编辑并没有让您更清楚您要做什么,而且您当前的方法本质上是错误的。我强烈建议您编辑澄清,否则我担心没有人能够正确地帮助您。
  • @Zeb:查看我的更新答案。至于具体的问题:只有在最近的更新中,您才明确提到您在使用 Perl 命令时遇到问题 - 为了帮助您解决这个问题,我们显然需要查看它和周围的代码;虽然所有这些都在您的原始问题中,但它缺少具体的问题描述。

标签: string bash shell


【解决方案1】:

Fedorqui's comment 是正确的,但你正在用它做一顿真正的饭!

要编辑您感兴趣的行,只需使用 Perl:

perl -pi -e 's/^\/\/// if /#define asdasd/' "$FILE"

这将读取您的文件并进行替换以从匹配模式/#define asdasd/ 的行的开头删除斜杠。

在这种情况下并不短,但您也可以将这两种模式结合起来,如下所示:

perl -pi -e 's/^\/\/(.*#define asdasd)/\1/' "$FILE"

不清楚是否要求只执行一次替换,但如果是,您可以将命令更改为:

perl -pi -e 's/^\/\/// if /#define asdasd/ && !$n++' "$FILE"

!$n++ 仅在第一次评估时为真,因此只会执行一次替换。

【讨论】:

  • 正如我在上面的评论中所写,我的问题比这段代码更复杂。我只想取消注释(删除双斜杠)与模式匹配的一行,而不一定是第一行。这就是为什么我不能对整个文件进行操作,而是逐行操作的原因。
  • 在这种情况下,您需要编辑您的问题,以便更清楚地了解替换的条件。在不知道为什么必须这样的情况下,我们无法根据您当前的方法提出解决方案。我无法想象在while read 循环中调用 perl 会是个好主意,尤其是在同一个文件上。
  • 刚刚完成!首先感谢您的帮助。我的问题非常具体,我正在寻找替代问题的解决方案,而不是我所有的算法方法。下次我会解释我所有的问题。
【解决方案2】:

如果您确实需要逐行处理文件,这里是如何解决读取和写入同一文件的问题 在循环中,@fedorqui 在评论中指出(代码使用bash 语法):

while IFS= read -r line; do
  if [[ $line == *"#define asdasd"* ]]
  then
    # ... process "$line" and update "$FILE"
  fi
done <<<"$(< "$FILE")"
  • "$(&lt; $FILE)"预先读取整个文件,然后使用here-string 将其通过管道传送到while 循环的标准输入。
    • 由于一次读取整个文件,因此不建议使用这种方法处理大型输入文件。
    • 附带说明:最好不要使用全大写的变量名,例如 $FILE,以防止与环境/特殊 shell 变量发生冲突。
  • 还请注意,我已经使 read 命令更加健壮:IFS= 表示保留前导和尾随空格(您可能想要也可能不想要),-r 确保 \ 实例不不要被read“吃掉”。

至于循环内的代码

  • new=${line#$prefix}// 的开头删除$line,因为你已经转义 / 字符。分配给$prefix - 改用prefix='//'。请注意,$line$new 中的任何未转义的 / 总是会破坏您的 perl 命令 - 其他字符。也可能导致问题:请参阅下一点。

  • sub="s/$line/$new/g" 是构造替换命令的一种脆弱方式,因为如果$line 和/或$new 恰好包含在上下文中具有特殊含义的字符如果使用正则表达式和替换字符串,甚至只是 分隔符 字符串 /,则该命令将出现异常或中断

  • 您可以使用以下 bash 函数(解释 here ]:
# SYNOPSIS
#   quotePerlRe <text>
quotePerlRe() { sed -e 's/[^^\\$]/[&]/g; s/\^/\\^/g; s/\\/\\\\/g; s/\$/\\$/g; $!a\'$'\n''\\n' <<<"$1" | tr -d '\n'; }
# SYNOPSIS
#  quotePerlSubst <text>
quotePerlSubst() {
  IFS= read -d '' -r < <(sed -e ':a' -e '$!{N;ba' -e '}' -e 's/[$/\]/\\&/g; s/\n/\\&/g' <<<"$1")
  printf %s "${REPLY%$'\n'}"
}

然后您可以按如下方式调用它们:

local sub="s/$(quotePerlRe "$line")/$(quotePerlSubst "$new")/g"

【讨论】:

    【解决方案3】:

    你能用 sed 来做这个吗

    sed -i -e '/#define asdasd/ s,^//,,' $FILE
    

    所以你只会匹配你想要的模式,然后删除双斜线。

    【讨论】:

      猜你喜欢
      • 2017-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 2014-07-18
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多