我想删除一行开头的双斜杠来取消对一行代码的注释,例如第一行注释。我的方法适用于许多其他情况,但这次还不够。这是我的文件中的一段代码。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文件,删除所选行开头的双斜杠。
Fedorqui的评论很中肯,但你正在用它做一顿真正的饭!
要编辑您感兴趣的行,只需使用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++
只有在第一次评估时才为真,因此只进行一次替换。
如果您真的需要逐行处理文件,下面是如何解决@fedorqui在评论中指出的在循环中读取和写入同一文件的问题(代码使用bash
语法):
while IFS= read -r line; do
if [[ $line == *"#define asdasd"* ]]
then
# ... process "$line" and update "$FILE"
fi
done <<<"$(< "$FILE")"
"$(< $FILE)"
读取整个文件,然后使用here字符串将其管道传输到while
循环的stdin。- 由于整个文件都是一次读取的,因此这种方法对于巨大的输入文件是不可取的
- 附带说明:最好不要使用所有大写的变量名,如
$FILE
,以防止与环境/特殊shell变量发生冲突
- 还要注意的是,我已经使
read
命令更加健壮:IFS=
意味着保留了前导和尾部空白(您可能想要也可能不想要),而-r
确保实例不会被
read
"吃掉">
至于循环中的代码:
new=${line#$prefix}
不会从$line
开始剥离//
,因为您已转义了/
字符。分配给CCD_ 18-改为使用CCD_ 19。请注意,$line
或$new
中任何未标记的/
都会破坏您的perl
命令-其他字符。也会引发问题:见下一点。sub="s/$line/$new/g"
是构造替换命令的一种脆弱的方式,因为如果$line
和/或$new
碰巧在正则表达式和替换字符串的上下文中包含具有特殊含义的字符,甚至只是分隔符字符串/
,则该命令将行为不端或中断。- 您可以使用以下
bash
函数执行字符串的安全转义,以便在perl
的s///
中使用(此处对此进行解释):
# 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"
你能像一样使用sed吗
sed -i -e '/#define asdasd/ s,^//,,' $FILE
所以你只需要匹配你想要的模式,然后去掉双斜线。