Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 替换多行“&引用;用一个“&引用;_Bash_Sed_Replace - Fatal编程技术网

Bash 替换多行“&引用;用一个“&引用;

Bash 替换多行“&引用;用一个“&引用;,bash,sed,replace,Bash,Sed,Replace,我正在使用sed清理Cisco交换机中的“show tech”或“Config”。有时在查看配置部分时,会有多行带有“!”标记。我不想删除所有的!因为这会改变配置,但我不需要只包含行的大型组!马克 简言之,与其说: !interface vlan200 !description ! ! ! interface vlan201 我想清理一下,以便: !interface vlan200 !description ! interface vlan201 我意识到我可以更换/卸下!使用 sed

我正在使用sed清理Cisco交换机中的“show tech”或“Config”。有时在查看配置部分时,会有多行带有“!”标记。我不想删除所有的!因为这会改变配置,但我不需要只包含行的大型组!马克

简言之,与其说:

!interface vlan200
!description 
!
!
!
interface vlan201
我想清理一下,以便:

!interface vlan200
!description
!
interface vlan201
我意识到我可以更换/卸下!使用

sed 's/^!//g'
这将删除该选项!从每行的开头开始

想法

#!/usr/bin/env bash
last_line=''
while IFS= read -r line; do
  [[ $line = '!' && $last_line = '!' ]] && continue
  printf '%s\n' "$line"
  last_line=$line
done
请参阅在运行时显示的,输出为:

!interface vlan200
!description 
!
interface vlan201
救援人员:

perl -ne 'print unless /^!$/ and $previous; $previous = /^!$/' -- file
  • -n
    逐行读取输入
  • 如果当前行包含单个
    ,则变量
    $previous
    设置为true,其值在处理下一行时用于决定是否打印它

根据OP的要求使用sed:

sed -nr 'p;:loop;$!N;s/^(\!)\n\1$/\1/;tloop;D'
注意:这是sed的一个常用一行代码的次要调整(仅匹配感叹号),可在此处找到:

所列代码中的另一个调整-

这源于

 sed '$!N; /^\(!\)\n\1$/!P; D'

 # delete duplicate, consecutive lines from a file (emulates "uniq").
 # First line in a set of duplicate lines is kept, rest are deleted.
 sed '$!N; /^\(.*\)\n\1$/!P; D'

解释
  • 伙计们,看看这个。 用于引用,因为它很好,这里似乎没有任何内容与其他版本冲突
N

向模式空间添加换行符,然后将下一行输入追加到模式空间。如果没有更多的输入,那么sed将退出,而不处理更多的命令

添加新的!地址规范末尾的字符(在命令字母之前)否定匹配的意义。也就是说,如果!字符跟在地址或地址范围之后,则只会选择与地址不匹配的行

$是文件的结尾,因此
$!N
表示在不是文件末尾最后一行的行上,“向模式空间添加换行符,然后将下一行输入附加到模式空间。”这使模式空间成为“这一行和下一行”

p

打印出直到第一个换行符的图案空间部分

所以,
/^\(.*\)\n\1$/!P表示将第一行从开头复制到换行符,并将其用作模式的\1反向引用,这意味着匹配两个相同的连续行。如果不匹配(代码)/!
),则打印第一行。如果它们匹配,它就不会打印

D

如果模式空间不包含换行符,则开始一个正常的新循环,就像发出了d命令一样。否则,删除模式空间中直到第一个换行的文本,并使用生成的模式空间重新开始循环,而不读取新的输入行

模式末尾的
D
从第一行移出,但留下附加到模式空间的第二行

所以从字面上说,它遍历文件,比较连续的行,只有当它们不相同时才打印它们

一个稍微简单一点的版本(如中所述,可能更容易阅读,尽管它仍在做几乎同样多的工作)是

这硬编码的球拍模式,至少不存储和使用的反向参考,虽然它仍然在移动它的方式通过所有的线。当我们看到一个单独的球拍时,我们可以通过堆叠线条来减少一些工作量:

sed '/^!$/N; /^!\n!$/!P; D'
p和D仍然在做他们的事情。:)

所以我们回到了我在顶部发布的模式。
希望有帮助。

sed是用来做s/old/new的,就是这些

$ awk '$0!=p || $0!="!"; {p=$0}' file
!interface vlan200
!description
!
interface vlan201
以上内容将适用于任何UNIX设备上任何shell中的任何awk。它只是说如果当前行与最后一行不同,或者当前行不是
然后打印它。然后,它保存当前行以与下一行进行测试。

这可能适用于您(GNU-sed):


打开一个两行窗口,如果第一行和第二行以
开头和结尾删除(不要打印)第一个。

感谢您及时回复。我刚刚开始再次尝试脚本编写,虽然这可能会奏效,但有一个单行解决方案来实现这一点是很有帮助的。此外,我也不知道如何将其应用于我想要处理的文件。但我相信那是我自己的错!re:应用这个--
/scriptname outfile
就可以了。或者,您可以将这些重定向直接放在
完成后的(同一行)上。感谢您继续使用sed。。。。然而,perl解决方案似乎确实可以解决这个问题。感谢sed链接,我相信这将在未来有所帮助!谢谢,我也喜欢perl,但还不够用。几年后,我又开始玩bash shell脚本了。。。谢谢,这个有用!
sed '/^!$/N; /^!\n!$/!P; D'
$ awk '$0!=p || $0!="!"; {p=$0}' file
!interface vlan200
!description
!
interface vlan201
sed 'N;/^!\n!$/!P;D' file