1

我有一个相当大的 csv 文件,其中每一行都应该以管道 (|) 结尾,如果它没有将下一行合并到其中,直到再次找到管道。这需要使用 shell 脚本来完成。

我得到了一个答案

awk '!/|$/{l=l""$0|next|}{print l""$0|l=""}' file

但这给了我错误,因为每行的大小对我来说都很大。我发现我应该使用 perl 来做到这一点,并尝试了以下方法,但它确实产生了预期的结果。

perl -pe 's/^\n(|\n)/ /gs' input.csv > output.csv

我的数据看起来像

A|1|abc|<xml/>|
|2|def|<xml
>hello world</xml>|
|3|ghi|<xml/>|

并且期望的输出应该是

A|1|abc|<xml/>|
|2|def|<xml>hello world</xml>|
|3|ghi|<xml/>|

显然,行大小比这里的样本输入要大。

任何帮助将不胜感激。

4

3 回答 3

1
awk '{printf "%s",$0} /[|][[:space:]]*$/ {print ""}' 

打印没有换行符的每一行。如果最后一个非空白字符是管道,则您有一个完整的行,因此打印一个换行符。

于 2013-01-18T16:12:07.640 回答
0

这应该有效:

perl -lne 'unless(/\|$/){$line=$line.$_}else{print $line." $_";undef $line}' your_file

如果您想进行就地替换,请执行以下操作:

perl -i -lne 'unless(/\|$/){$line=$line.$_}else{print $line." $_";undef $line}' your_file

在此处查看您的评论

于 2013-01-18T14:10:47.043 回答
0

这应该很乐意为您处理所有情况,并且不会在任何行长上中断:

#!/bin/bash
newLine=0
IFS=
while read -r -n 1 char; do
    if [[ $char =~ ^$ ]]; then
        if [[ $newLine -eq 1 ]]; then
            newLine=0
            echo '|' # add a newline
        fi  
    elif [[ $char =~ . && ( $newLine -eq 1 ) ]]; then
        newLine=0
        echo -n "|$char"
    elif [[ $char =~ [|] ]]; then
        if [[ $newLine -eq 1 ]]; then
            echo -n '|'
        fi  
        newLine=1
    else
        echo -n $char
    fi  
done < file.txt

请注意,在 bash 中手动构建词法分析器通常是一个坏主意。

于 2013-01-18T15:06:17.850 回答