我有一个数据库卸载文件与<TAB>字符分隔的字段。 我通过sed运行这个文件,用<TAB> \ N <TAB>replace<TAB> <TAB>的任何出现。 这是这样的,当文件被加载到MySQL的\ N在解释为NULL。
sed命令的/ \ t \ t / \ t \ N \ t / g;' 除了它只replace第一个例子,例如“… <TAB> <TAB> <TAB> …”变成“… TAB N N TAB TAB …”。
如果我用't \ t \ t \ n \ t \ g; s \ \ t \ t \ t \ n \ t \ g;' 它取代了更多的实例。
我有一个概念,尽pipe/ g修饰符这是一个匹配的结束是另一个的开始。
任何人都可以解释发生了什么事情,并build议一个将工作或我需要循环的sed命令。
我知道我可以切换到awk,perl,python,但是我想知道sed中发生了什么。
我知道你想要sed,但是sed根本不喜欢这个,看起来它特意(见这里 )不会做你想要的。 但是,Perl会做到这一点(AFAIK):
perl -pe 'while (s#\t\t#\t\n\t#) {}' <filename>
解决方法是将每个选项卡替换为选项卡+ \ N; 然后删除所有不是紧跟在标签后面的\ N。
sed -e 's/\t/\t\\N/g' -e 's/\\N\([^\t]\)/\1/g'
…提供您的sed在分组括号之前使用反斜线(有不想反斜杠的sed方言;如果这不适合您,请尝试没有它们)。
正确,即使使用/g
,sed也不会匹配再次替换的文本。 因此,读取<TAB><TAB>
并输出<TAB>\N<TAB>
,然后从输入流中读取下一个内容。 请参阅http://www.grymoire.com/Unix/Sed.html#uh-7
在一个支持lookahead的正则表达式语言中,你可以用前瞻来解决这个问题。
那么, sed
只是按照设计工作。 输入行被扫描一次,而不是多次。 如果sed
默认使用重新扫描输入行来处理重叠模式,那么可能有助于看看后果:在这种情况下,即使是简单的替换也会有很大不同 – 有些人可能会反直觉地说 – 例如
s/^/ /
在行的开头插入一个空格将永远不会终止 s/$/foo/
将foo附加到每行 – 同样 s/[AZ][AZ]*/CENSORED/
用s/[AZ][AZ]*/CENSORED/
替换大写字母 – 同样 可能还有很多其他情况。 当然,这些都可以用一个替代修饰符来补救,但是在设计sed时,选择了当前的行为。
没有不同的Perl解决方案,这对我使用纯粹的sed
sed ':repeat; /\t\t/{ s|\t\t|\t\n\t|g; b repeat }'
:repeat
是一个标签,用于分支命令,类似于批处理 /\t\t/
表示匹配模式2选项卡。 如果匹配的模式,第二个/之后的命令被执行。 {}
– 在这种情况下,match命令之后的命令是一个组。 因此,如果匹配模式被满足,则组中的所有命令都被执行。 s|\t\t|\t\n\t|g;
– 标准用tab-newline-tab替换2个选项卡。 我仍然使用全局的,因为如果你有15个选项卡,你只需要循环两次,而不是14次。 b repeat
意味着总是转到(分支)标签repeat
所以它是这样的。 只要有两个选项卡的模式匹配,请继续重复( repeat
)。
虽然可以说你可以做两个完全相同的全局替换并称之为好,但是同样的技术可以在更复杂的情况下工作。
正如@ thorn-blake指出的那样,sed只是不支持像lookahead这样的高级功能,所以你需要像这样做一个循环。
这可以缩短到
sed ':r;/\t\t/{s|\t\t|\t\n\t|g; br}'
和Mac(但仍然Linux / Windows兼容)版本:
sed $':r\n/\t\t/{ s|\t\t|\t\\\n\t|g; br\n}'