줄 바꿈을 레코드 구분 기호로 사용하는 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
또 다른 GNU awk
솔루션은 각 레코드에 |
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
각 호출에 t를 추가합니다print
.-ne
: 입력 파일을 한 줄씩 읽고 주어진 스크립트를-e
각 줄에 적용합니다.$#F==1 ? printf : print'
:$#F
변수는 배열의 요소 수@F
, 즉 필드 수입니다. 따라서 이는 필드 수가 1인 경우(기존 줄이 제거되고 하나가 추가되지 않으므로 개행 없이 현재 줄을 인쇄함)를 의미 합니다printf
. 필드 수가 정확히 1이 아닌 경우 줄 바꿈이 추가되기 때문입니다 .-l
printf
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'