在条件下删除上一行的最后一个字符

时间:2016-07-13 17:44:37

标签: bash perl sed

使用bash,从下面的F90代码中,我尝试删除最后一个"&"如果下一行以" AA"开头(注意AA之前的空白)。

     F = 2 * 3 * a * b * 7&
    & * 3 * b * c
     AA = ...

应该成为

perl -0pe 's/\&\n\s*AA/\nAA/g' $MYFILE

Bash - Remove the last character of the line this before?的建议。 基于此,我尝试了

sed -i 's/\&\n\s*AA/\nAA/g' $MYFILE

以及

\s*

不会产生任何错误,但也不会改变任何错误。我也试过没有<UserControl ...> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock><Run Text="Some text"/></TextBlock> <ScrollViewer Grid.Row="1" CanContentScroll="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" MinWidth="{Binding ActualWidth, BindsDirectlyToSource=True, ElementName=userControl, Mode=OneWay}">

3 个答案:

答案 0 :(得分:3)

使用sed

使用GNU sed:

$ sed -z 's/&\n AA/\n AA/g' file
 F = 2 * 3 * a * b * 7&
& * 3 * b * c
 AA = ...

为了简化此命令,我们使用-z选项一次读入整个文件。 (从技术上讲,-z读取NUL分隔的输入。由于没有有效的Fortran文件包含NUL,因此具有读取整个文件的效果。)

s/&\n AA/\n AA/g执行我们想要的替换。文件包含&后跟换行符后跟空格后跟AA的任何地方,此替换会移除&

如果文件太大而无法放入内存中,那么立即读取整个文件并不是一个好方法。对于Fortran文件,这不应该是一个问题。

对于非GNU sed(BSD,OSX),我们需要添加代码来替换-z标志:

sed 'H;1h;$!d;x;  s/&\n AA/\n AA/g' file

使用awk

$ awk '{if (/^ AA/) sub(/[&]$/, "", last); if (NR>1) print last; last=$0} END{print last}' file
 F = 2 * 3 * a * b * 7&
& * 3 * b * c
 AA = ...

工作原理:

此脚本使用一个变量last,其中包含上一行的内容。如果当前行以AA开头,则我们会从&中删除最终last(如果有)。更详细:

  • if (/^ AA/) sub(/&$/, "", last)

    如果当前行以AA开头,则从上一行中删除最后的&

  • if (NR>1) print last

    如果我们不在第一行,则打印上一行。

  • last=$0

    将当前行保存为last

  • END{print last}

    在我们到达文件末尾后,请打印last

就地更改文件

使用GNU sed:

sed -zi.bak 's/&\n AA/\n AA/g' file

使用其他sed:

sed -i.bak 'H;1h;$!d;x;  s/&\n AA/\n AA/g' file

最近的GNU awk:

awk -i inplace '{if (/^ AA/) sub(/&$/, "", last); if (NR>1) print last; last=$0} END{print last}' file

使用较旧的awk或非GNU awk:

awk '{if (/^ AA/) sub(/&$/, "", last); if (NR>1) print last; last=$0} END{print last}' file >file.tmp && mv file.tmp file

答案 1 :(得分:3)

如果将整个文件加载到内存中会变得非常容易(因为-0777原因)。

perl -0777pe's/&(?=\n[^\S\n]*AA)//g'

在不将整个文件加载到内存中的情况下使用滑动窗口完成。

perl -ne'$p=~s/&(?=\n)// if /^\s*AA/; print $p; $p=$_; END { print $p }'

perl -pe'print $s if !/\s*AA/; $s = s/&\n// ? $& : ""; END { print $s }'

所有三个在AA之前接受任意数量的空格和制表符。

用法:

perl ... file.in >file.out    # From a file
perl ... <file.in >file.out   # From STDIN
perl -i~ ... file             # "In-place", with backup
perl -i ... file              # "In-place", without backup

答案 2 :(得分:0)

这可能适合你(GNU sed):

sed -r 'N;s/&([^&]*\n\s*AA)/\1/;P;D' file

在模式空间(PS)中读取两行,并使用模式匹配从第一行删除&,如果第二行开始(少于空白)AA

N.B。这适用于第二行也包含&等等......