如何仅从文件中删除第一行行?

时间:2019-09-05 15:48:43

标签: linux sed command-line

还有一个类似的问题:sed search a range and print first set,但对于我的一生,我不知道如何适应我的情况。

如果我定义的配置文件大致如下:

define global {
alias=main
icon_size=20
object_id=0
map_image=net_map_only.jpg
grid_show=0
}

define line {
x=6c4e2f%+10,5dd361%+10
y=6c4e2f%+10,5dd361%+10
z=90
object_id=2d6bec
view_type=line
line_type=11
line_width=1
line_color=#000000
}

#define line {
#x=266424%+10,604bc6%+10
#y=266424%+10,604bc6%+10
#z=90
#object_id=5b6082
#view_type=line
#line_type=11
#line_width=1
#line_color=#000000
#}

define host {
host_name=INTERNET
x=519
y=307
z=98
object_id=6c4e2f
iconset=std_medium
icon_size=20
label_show=1
label_background=#ffffff
label_border=transparent
label_maxlen=14
}


define host {
host_name=INTERNET
x=519
y=307
z=98
object_id=6c4e2f
iconset=std_medium
icon_size=20
label_show=1
label_background=#ffffff
label_border=transparent
label_maxlen=14
}

如上所示,有多个主机条目,还有许多其他条目(定义行,定义全局等)。条目的定义是从正则表达式"^define host"开始到下一个"}"

出于调试目的,我只想选择性地注释或删除第一个主机条目。我将遍历彼此的主机条目并检查错误,因此我想从命令行进行操作。

我的最初想法是:

sed -i '/^define host/,/}/s/^/#/' config.txt

可完美注释所有主机配置行。

但是,我似乎无法获得它,如何适应它,使其仅对第一个匹配的配置条目执行此操作。可能吗

4 个答案:

答案 0 :(得分:3)

IIUC:

sed '1,/\}/{s/^/#/}' config.txt

示例输出:

#define host {
#host_name=INTERNET
#x=519
#y=307
#z=98
#object_id=6c4e2f
#iconset=std_medium
#icon_size=20
#label_show=1
#label_background=#ffffff
#label_border=transparent
#label_maxlen=14
#}

define host {
host_name=INTERNET
x=519
y=307
z=98
object_id=6c4e2f
iconset=std_medium
icon_size=20
label_show=1
label_background=#ffffff
label_border=transparent
label_maxlen=14
}

define host {
host_name=INTERNET
x=519
y=307
z=98
object_id=6c4e2f
iconset=std_medium
icon_size=20
label_show=1
label_background=#ffffff
label_border=transparent
label_maxlen=14
}

OP修改了示例输入,并指出define host {没有 到文件顶部。在这种情况下,以下命令应该起作用:

sed '/^define host/{:a /^$/{:b ;n;bb}; s/^/#/;;n;ba}' config.txt

基于示例输入的示例输出提供了OP:

define global {
alias=main
icon_size=20
object_id=0
map_image=net_map_only.jpg
grid_show=0
}

define line {
x=6c4e2f%+10,5dd361%+10
y=6c4e2f%+10,5dd361%+10
z=90
object_id=2d6bec
view_type=line
line_type=11
line_width=1
line_color=#000000
}

#define line {
#x=266424%+10,604bc6%+10
#y=266424%+10,604bc6%+10
#z=90
#object_id=5b6082
#view_type=line
#line_type=11
#line_width=1
#line_color=#000000
#}

#define host {
#host_name=INTERNET
#x=519
#y=307
#z=98
#object_id=6c4e2f
#iconset=std_medium
#icon_size=20
#label_show=1
#label_background=#ffffff
#label_border=transparent
#label_maxlen=14
#}


define host {
host_name=INTERNET
x=519
y=307
z=98
object_id=6c4e2f
iconset=std_medium
icon_size=20
label_show=1
label_background=#ffffff
label_border=transparent
label_maxlen=14
}

答案 1 :(得分:2)

这可能对您有用(GNU sed):

sed '/^define host/{x;s/^/x/;x};//,/^}/{x;/^x\{1\}$/{x;d};x}' file

在范围的开始处在保留空间中增加一个计数器,并根据范围删除范围,例如这将从行define host到行}的行中的行范围中的第一个出现。

此解决方案可以扩展为删除一个范围范围或一组范围:

sed '/^define host/{x;s/^/x/;x};//,/^}/{x;/^x\{2,3\}$/{x;d};x}' file

这将删除上述范围的第二和第三次出现。

sed '/^define host/{x;s/^/x/;x};//,/^}/{x;/^\(x\{2\}\)*$/{x;d};x}' file

这甚至会删除上述范围内的东西。

答案 2 :(得分:2)

ed非常适合就地编写文件的脚本,而无需像sedawk那样一次处理一行:

ed -s foo.cnf <<EOF
/^define host/;/^}$/ s/^/#/
w
EOF

或在交互式Shell会话中

$ ed -s foo.cnf
/^define host/;/^}$/ s/^/#/
wq

将注释第一块中的每一行,并以define host开始,最后以}结尾。请注意,它与您尝试的sed非常相似,但是地址范围仅适用于第一个匹配的块,而不是像sed一样适用于所有匹配的块。

答案 3 :(得分:1)

sed在单行操作中很有用。尽管您想要的东西可以用sed完成,但这会非常痛苦。

注意,很好地了解sed可能非常有用,本质上它与awk具有相似的脚本语言。但是awk更接近当前的高级语言,并且使用它更容易创建复杂的过滤器。

如果我很了解您的问题,则只需要在所有行之前放置一个“ #”,直到第一个单行“ }”为止。 “ define host {”部分仅是冗余信息(尽管您可以根据需要将其添加到脚本中)。可以使用以下awk脚本轻松完成此操作:

awk '
  BEGIN {
    PREF="#";
  };

  {
    print PREF $0;
  };

  /^\}$/ {
    PREF="";
  };
'

遵循awk的逻辑的最佳做法:

  • 您有一个局部变量列表,这些变量定义了当前程序的内部状态
  • 对于输入的所有行,awk检查所有命令块中的正则表达式。如果匹配,则执行该块。检查执行按照在awk脚本中声明的顺序进行。
  • BEGIN总是在读取第一行之前被调用,END在最后一行之后被调用,如果您在块之前不使用正则表达式,则所有行都将被调用。

如果需要,您甚至可以在awk中开发复杂的软件,但这不是awk的目的。