我有一个包含 150 多列的 CSV 文件,其中使用换行符作为记录分隔符。问题在于其中一列获得换行符。为此,我想删除这些。
输入:
001|Baker St.
London|3|4|7
002|Penny Lane
Liverpool|88|5|7
输出:
001|Baker St. London|3|4|7
002|Penny Lane Liverpool|88|5|7
答案1
sed
只要当前行不包含 4 个|
字符,您就可以将下一行合并到当前行中:
<file sed -e :1 -e 's/|/|/4;t' -e 'N;s/\n/ /;b1'
某些sed
实现具有-i
或-i ''
可以就地编辑文件(-i.back
以使用扩展名保存原始文件.back
),因此使用这些实现,您可以执行以下操作:
sed -i -e :1 -e 's/|/|/4;t' -e 'N;s/\n/ /;b1' ./*.csv
编辑csv
当前目录下的所有非隐藏文件。
与评论相同:
<file sed '
:1
s/|/|/4; # replace the 4th | with itself. Only useful when combined with
# the next "t" command which branches off if the previous
# substitution was successful
t
# we only reach this point if "t" above did not branch off, that is
# if the pattern space does not contain 4 "|"s
N; # append the next line to the pattern space
s/\n/ /; # replace the newline with a space
# and then loop again in case the pattern space still does not contain
# 4 "|"s:
b1'
答案2
依赖于第一个字段的格式(假设每行应以数字开头):
awk 'NR == 1{ printf $0; next }
{ printf "%s%s", (/^[0-9]+/? ORS : ""), $0 }
END{ print "" }' file.csv
输出:
001|Baker St.London|3|4|7
002|Penny LaneLiverpool|88|5|7
答案3
另一个 GNUawk
解决方案依赖于|
每条记录 4 次:
awk -v RS='([^|]+\\|){4}[^|]+\n' '{gsub(/\n/," ",RT); print RT}' file
RS
设置为记录包含 4 个分隔符(即使有换行符)。
RT
追上了 所创造的记录RS
。gsub
删除记录上的换行符。
答案4
如果我们可以假设任何只有 2 个字段的行都应该删除其尾随换行符,则可以在 Perl 中执行以下操作:
$ perl -F"\|" -lane '$#F==1 ? printf : print' file.csv
001|Baker St.London|3|4|7
002|Penny LaneLiverpool|88|5|7
重要免责声明:正如 Stéphane Chazelas 的评论中所指出的,这假设您的输入不包含任何%
字符,因为如果包含任何字符,这些字符将被视为 的格式说明符printf
。这可能会产生意想不到的后果,从简单地打印错误的输出到吃东西负载RAM,如果你的输入有一些愚蠢的东西,比如%02147483600f%02147483600f%02147483600f%02147483600f
.
解释
-a
: 使perl
行为类似于awk
,在给定的字符上分割每个输入行-F
(因此,|
这里是 a;需要转义,因为\|
因为|
在 perl 正则表达式中意味着 OR)并将结果保存为数组@F
。-l
:这会从每个输入行中删除尾随换行符,并'n
在每次调用时添加一个 tprint
。-ne
:逐行读取输入文件并将给定的脚本应用于-e
每一行。$#F==1 ? printf : print'
:$#F
变量是数组中元素的数量@F
,即字段的数量。因此,这意味着如果字段数为 1,则printf
(这将打印当前行而不带换行符,因为现有行已被删除-l
并且printf
不会添加一个)。如果字段数不正好为 1,print
则该行(因为-l
将添加换行符)。
同样的事情可以扩展到:
$ perl -e 'while($line=<STDIN>){
chomp $line;
@fields=split(/\|/,$line);
if(scalar(@fields) == 2){
print "$line";
}
else{
print "$line\n"
}
}' < file.csv
001|Baker St.London|3|4|7
002|Penny LaneLiverpool|88|5|7
@Sundeep 在评论中建议了一个更短的版本:
perl -F'\|' -ape 'chomp if $#F==1'