Tux*_*ife 6 bash regex sed awk
使用“*”符号,(不必是那个,任何特殊字符都可以表示),我如何编辑文本:
*berry
straw
rasp
blue
boysen
*
blahblah
blahblah
blahblah
*berry
straw
blue
*
blah
*table
vege
pingpong
*
Run Code Online (Sandbox Code Playgroud)
对此:
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
Run Code Online (Sandbox Code Playgroud)
第一个匹配星号之后的每个字符都将放置在每一行上,直到找到第二个星号匹配项。
关于我如何解决这个问题的任何线索?(最好使用 sed 或 awk,但如果您能想到其他方法,请将您的代码发给我!)
我知道如何删除所有包含星号的行,这只是我想不到的字符放置部分
mur*_*uru 12
这段awk
代码就足够了:
awk -F'*' 'NF == 2 {label = $2; next} {$0 = $0 label} 1'
Run Code Online (Sandbox Code Playgroud)
分解:
*
作为字段分隔符。这样,我们可以简单地检查字段数 ( NF
) 以确定是否到达块的开头或结尾。label
并继续下一行。label
到当前行,然后打印。如果标签为空,我们就在一个块之外,没有任何影响。如果没有,我们会得到所需的输出。在 中sed
,您可以在删除“特殊”行之前将其复制到保留空间中
sed -e '/^\*/{h;d;}'
Run Code Online (Sandbox Code Playgroud)
然后将保留空间附加到每个后续的模式空间,替换生成的换行符和标记字符
-e '{G;s/\n\*//;}'
Run Code Online (Sandbox Code Playgroud)
用你的数据测试它,
$ sed -e '/^\*/{h;d;}' -e '{G;s/\n\*//;}' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
Run Code Online (Sandbox Code Playgroud)
注意:这不会在遇到第二个星号时停止;它的作用完全相同,但它附加*
后什么都没有 - 直到它匹配下一个*sometext
.
这是一种 Perl 方式:
$ perl -lne '/^\*(.*)/ || print "$_$1"' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
Run Code Online (Sandbox Code Playgroud)
这-n
将导致 Perl 读取输入文件的每一行,将其保存在特殊变量中$_
,这-l
将导致它 i \n
) 从每一行中去除尾随的换行符 ( ) 和 ii) 向print
. 的-e
是施加于每行的脚本。
/^\*(.*)/
: 匹配以星号开头的行并将星号后的所有内容另存为$1
(这就是括号的作用)。
|| print "$_$1"'
:||
是合乎逻辑的OR
。因此,print
只有当当前行不以星号开头时才会执行。如果是这样,我们打印当前行 ( $_
) 以及当前保存的任何内容$1
(星号后面的模式)。
像往常一样,有很多方法可以做到这一点。一个愚蠢且低效但突出了 shell 的字符串操作功能的方法是:
$ while read line; do
[[ $line =~ ^\* ]] && pat="${line#\*}" || printf "%s%s\n" "$line" "$pat";
done < file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable
Run Code Online (Sandbox Code Playgroud)
while read line; do ... ; done < file
:这是一个经典的while
循环,它将读取输入文件的每一行file
并将其保存为$line
.[[ $line =~ ^\* ]] && pat="${line#\*}"
: 如果该行以 an 开头*
,则删除之后的所有内容(这就是它的${line#\*}
作用,有关更多详细信息,请参见此处)并将其另存为$pat
. * || printf "%s%s\n" "$line" "$pat";
:如果前一个命令失败(因此,该行不以星号开头),则打印该行和 的当前值$pat
。