我有一个数据库卸载文件,其字段用< TAB>分隔。字符。我通过sed运行此文件来替换< TAB>< TAB>的任何出现。 < TAB> \ N< TAB>。这样,当文件加载到MySQL时,\ N被解释为NULL。
sed命令的/ \ t \ t / \ t \ N \ t / g;'几乎可以工作,只是它只替换第一个例子,例如“...< TAB>< TAB>< TAB> ...”变为“...< TAB> \ N< TAB>< TAB> ...”。
如果我使用's / \ t \ t / \ t \ N \ t / g; s / \ t \ t \ \ t \ n \ t \ N \ t / g;'它取代了更多的实例。
我有一个想法,尽管/ g修饰符,这与一个匹配的结束是另一个匹配的开始有关。
任何人都可以解释发生了什么,并建议一个可以工作的sed命令,或者我需要循环。
我知道我可能会切换到awk,perl,python,但我想知道sed中发生了什么。
答案 0 :(得分:2)
我知道你想要sed,但是sed完全不喜欢这个,它似乎特别(见here)不会做你想要的。但是,perl会这样做(AFAIK):
perl -pe 'while (s#\t\t#\t\n\t#) {}' <filename>
答案 1 :(得分:2)
作为解决方法,使用tab + \ N替换每个选项卡;然后删除所有出现的\ N,它们不会紧跟一个标签。
sed -e 's/\t/\t\\N/g' -e 's/\\N\([^\t]\)/\1/g'
...如果你的sed在分组括号之前使用反斜杠(有sed方言不需要反斜杠;如果这对你没用,请尝试不使用它们。)
答案 2 :(得分:1)
是的,即使使用/g
,sed也会与它再次替换的文本不匹配。因此,它读取<TAB><TAB>
并输出<TAB>\N<TAB>
,然后从输入流中读取下一个内容。见http://www.grymoire.com/Unix/Sed.html#uh-7
在支持前瞻的正则表达式语言中,您可以通过前瞻来解决这个问题。
答案 3 :(得分:1)
嗯,sed
只是按设计工作。输入行扫描一次,而不是多次。如果sed
使用重新扫描输入行来默认处理重叠模式,可能会有所帮助:在这种情况下,即使是简单的替换也会有不同的作用 - 有些人可能会反直觉地说 - 例如< / p>
s/^/ /
在行的开头插入一个空格永远不会终止s/$/foo/
将foo附加到每一行 - 同样s/[A-Z][A-Z]*/CENSORED/
用CENSORED替换大写单词 - 同样可能还有很多其他情况。当然,这些都可以用替代修饰符来解决,但在设计sed时,选择了当前的行为。
答案 4 :(得分:1)
与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
所以就是这样。只要匹配2个标签的模式,就不断重复(转到repeat
。
虽然可以说你可以做两个相同的全局替换并且称之为好,但是同样的技术可以在更复杂的场景中工作。
正如@ thorn-blake指出的那样,sed只是不支持像超前一样的高级功能,所以你需要像这样做一个循环。
可以缩短为
sed ':r;/\t\t/{s|\t\t|\t\n\t|g; b r}'
Mac(但仍然兼容Linux / Windows)版本:
sed $':r\n/\t\t/{ s|\t\t|\t\\\n\t|g; b r\n}'