빈 줄을 제거하기 위해 텍스트 파일을 필터링하는 좋은 방법은 무엇입니까?


11

빈 줄이 여러 개있는 .csv 파일 (Mac)이 있습니다. 예 :

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"

내가 변환하고 싶은 것 :

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum  lorem ipsum ","2","3","4"

라이너가 하나 있어야한다는 것을 알고 있지만 awk 나 sed는 모릅니다. 어떤 팁이라도 대단히 감사합니다!


1
이 샘플에 따르면 실제로 필드에서 포함 된 줄 바꿈을 제거하려고합니다. 그 맞습니까? 다시 말해, 6 개의 입력 라인이 있고 2 개의 출력 라인이어야합니까?
manatwork

그렇습니다. 이것은 내가 제거하려고하는 것입니다 : 인용 된 문자열 안에 포함 된 줄 바꿈.
pitosalas

따라서 필요한 것은 따옴표 안의 줄 바꿈을 제거하는 것입니다. 여러 줄 정규식이 필요하기 때문에 조금 더 복잡해질 것입니다.
tongpu

답변:


11

grep -v(반전 일치) 모드를 사용하여 다음을 수행 할 수 있습니다 .

grep -v '^$' old-file.csv > new-file.csv

셸 리디렉션이 작동하는 방식 때문에 파일이 서로 달라야합니다. 입력 파일을 읽기 전에 출력 파일을 열고 비 웁니다. 더 많은 유틸리티가있는 경우 (Mac OS X에서는 기본적으로 아님) sponge이 문제를 해결 하는 데 사용할 수 있습니다 .

grep -v '^$' file.csv | sponge file.csv

그러나 물론 무언가 잘못되면 되돌아 가기가 더 어려워집니다.

"공백 줄"에 실제로 공백이 포함되어있는 경우 (공백과 같이 들림) 대신 다음을 사용할 수 있습니다.

egrep -v '^[[:space:]]*$' old-file.csv > new-file.csv

공백 만 포함하고 공백 만 포함하는 행은 무시합니다. 물론 동일한 sponge변환을 수행 할 수 있습니다 .


감사합니다 .... 빈 줄을 삭제하지 않았습니다 ... ^ $이 일치하지 않을 수 있습니까? 그러나 내가 아는 한 그 줄은 비어 있습니다. 이것은 Mac에서 Excel로 만든 cdv라는 것을 기억하십시오. (내가 Excel이라고 말했기 때문에 비명을
지르지

@pitosalas 아마도 빈 줄이 아닐 것입니다. 로 변경합니다 egrep -v '^[[:space:]]*$'> egrep을하고 이상한 새로운 패턴 - 그렙 ... 참고
derobert

일하지 않았다. 큰 따옴표를 많이 삭제하고 엉망이되었습니다 ...
pitosalas

@pitosalas 큰 따옴표를 어떻게 삭제하는지 잘 모르겠습니다. 공백 만 삭제할 수 있어야합니다. 그리고 실제로 여러분이 게시 한 예제 데이터에서 테스트 할 때 수행하는 작업입니다.
derobert

@pitosalas를 사용하면 이러한 명령 중 하나가 횡설수설이 아닌 합리적으로 보이는 것을 내뱉는지 확인할 수 있습니다. iconv -f utf16le file.csv | head또는iconv -f utf16be file.csv | head
derobert

8

가장 쉬운 옵션은 grep .입니다. 여기에서 점은 "무엇이든 일치"를 의미하므로 선이 비어 있으면 일치하지 않습니다. 그렇지 않으면 그대로 전체 줄을 인쇄합니다.


6

ksh93을 사용하여 빈 줄 을 제자리에서 제거하려면 다음을 수행하십시오 .

sed '/./!d' file 1<>; file

<>;리디렉션 연산자 ksh93의 특정 표준과 동일 <>명령 후 파일이 종료되었는지의 KSH 자릅니다 제외 연산자.

sed '/./!d'은 복잡한 작성 방법 grep .이지만 불행히도 GNU grep은 stdout이 stdin과 동일한 파일을 가리키는 경우 적어도 불평합니다. 당신은 하나를 쓸 수 있다고 말할 것입니다 :

grep . file | cat 1<>; file

그러나 불행히도 ksh93 (적어도 내 버전 (93u +))에는 파일이 길이가 0으로 잘리는 것처럼 보이는 버그가 있습니다.

grep . file | { cat; } 1<>; file

이 버그를 해결하는 것처럼 보이지만 sed 명령보다 훨씬 복잡합니다.


각 솔루션을 언제 사용해야하는지에 대한 빠른 안내서와 함께 정답을 하나의 형식이 지정된 항목으로 결합하십시오. 부동 응답에서 모두 서로 다른 문제에 대한 다른 접근 방식으로 인해이 질문을 읽는 것은 약간의 재앙이되었습니다.
Caleb

@Caleb, 그것은 모든 질문이 매우 불분명 한 것으로 요약되어 있으므로 모든 사람의 대답은 질문에 대한 다른 해석에 대한 것입니다. 각 답변에 대해 어떤 질문에 대답하려고하는지 말하려고했습니다.
Stéphane Chazelas

참고로 awk '/./' file 1<>; file, 효과가있었습니다. 나에게 그것은 더욱 분명하다sed '/./!d'
grebneke

5

여기에 Perl하나의 라이너가 있습니다.

perl -pi -e 's/^\s*\n//' yourfile

편집 : 아래 ruakh의 의견을 기반으로 코드가 개선되었습니다.


1
또는perl -ni -e '/./ and print' yourfile
derobert

1
@peterph $는 앵커 (너비 0)이므로 개행을 제외합니다. 불필요한 공간에 관해서는 /x내가 Perl정규 표현식에`$ \`를 보간 하고 싶지 않다고 덧붙인 이유입니다.
Joseph R.

1
당신은 필요하지 않습니다 $당신이이 점을 감안 \n. (다른 방법 - 당신은 필요하지 않습니다 \n당신이이 점을 감안 \s*하고,을 $,하지만 내가 생각하는 s/^\s*\n//줄 바꿈이 제거되는 것을 그것을 명확 차종을.) 당신은 또한 필요하지 않습니다 /m; 이 명령에는 영향을 미치지 않습니다. 그리고 $공간을 제거하면가 필요하지 않습니다 /x.
ruakh

1
@JosephR .: \n자체 제거 할 수 있습니다. 당신이 할 수없는 것은 제거입니다 모두 $ \n . 그래서 s/^\s*//당신이 설명하는 문제가있다,하지만 s/^\s*$//때문에의, 잘 될 것 \s*하고 $. (내가 무슨 뜻인지
알겠 니

1
@JosephR .: 발생하는 것은 개행 전에 일치 $ 할 수 있으며 ( /m플래그가 사용 가능하거나 개행이 문자열의 마지막 문자이거나 둘 다인 경우), 문자열 의 끝과 일치 할 수 있습니다 . 예를 들어, "abc" =~ m/^abc$/사실입니다. 의 경우 \s*$는이 \s*줄 바꿈을 먹을 욕심 충분하다 다음은 $최종의 문자열과 일치합니다. (하지만 내가 생각하는 s/^\s*\n//당신의 대답은 잘 그것을 지금처럼 그래서, 어쨌든, 명확합니다.)
ruakh

5

귀하의 질문에 대한 의견의 설명을 바탕으로,

awk -v RS= -v ORS= 1

당신이 원하는 것을 할 수 있습니다.

레코드 구분 기호awk레코드가 단락 (빈 행 시퀀스로 구분됨) 임을 알려주는 특수한 경우입니다 . 출력 레코드 구분 기호 를 빈 문자열로 설정하면 해당 단락의 내용이 구분 기호없이 연결되어 있어야합니다. 모든 레코드를 인쇄하기 1위한 진정한 조건입니다.

그러나 후행 줄 바꿈을 생략하므로 다음을 수행 할 수 있습니다.

awk -v RS= -v ORS= '1;END{if (NR) printf "\n"}'

3

파일을 제공하면이 작업이 쉬워졌지만 안타깝게도 공유 할 수없는 기밀 정보가 포함되어있었습니다. 그동안 나는 속임수를 쓰는 것처럼 보이는 루비 스크립트를 작성했습니다.

require 'csv'
c = CSV.open("outfile1.csv", "w")
CSV.foreach("data.csv", :encoding => 'windows-1251:utf-8') do |row|
  row = row.map { |a| a.class == String ? a.gsub(/\r/, '') : a}
  c << row
end
c.close

도와 주셔서 감사합니다!


2
awk '
    length == 0 {next} 
    /^[^"]/ && /"$/ {print; next} 
    {printf("%s", $0)}
' filename

생산

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"

2

stackoverflow 에서 가능한 솔루션에 대한 아이디어를 찾았습니다 .

sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv

csv 파일을 테스트하기 전에 백업해야 할 수도 있지만 최소한 예제에서는 완벽하게 작동합니다.

이 표현의 내부 작업에 대한 좋은 설명이 답에 제공됩니다. 방금 "( [^"]\n)로 끝나지 않는 줄을 찾기 위해 편집했습니다 .


1

자신의 응답에서 인용 된 문자열 안에 포함 된 줄 바꿈 문자를 제거하려면 다음을 수행하십시오.

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse'

또한 사용 펄의 사용할 수있는 -i편집에 파일을 플래그를 제자리에 .

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse' file1 file2...

또는 GNU awk와 함께 :

 awk -v RS=\" 'NR%2==0 {gsub("\n","")}; {printf "%s", $0 RT}'

또는:

 awk -vRS=\" '1-NR%2{gsub("\n","")}{ORS=RT}1'

(가장 짧은 경쟁을하는 경우)

입력에 이스케이프 된 큰 따옴표 문자 가 없다고 가정합니다 .


0

실제로 빈 줄을 제거하는 것 이상을 원하지만 2 개 이상의 개행 문자의 모든 시퀀스를 제거하는 것처럼 보입니다.

펄로 할 수있는 것 :

perl -0777 -pe 's/\n{2,}//gs' file

또한 사용 펄의 사용할 수있는 -i편집에 파일을 플래그를 제자리에 .

perl -0777 -pi -e 's/\n{2,}//gs' file1 file2...

0

빈 줄을 제거하는 더 짧은 방법이 있습니다 AWK.

awk 'NF' file

그러나 원하는 출력을 얻으려면 간단한 하나의 라이너 만 있으면됩니다.

awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file

설명

에서 AWK빈 줄은 행 / 레코드에 필드가 없음을 의미합니다. 즉, NF(Number of Fields) 변수가 0입니다. 위의 한 NF > 0줄은 모든 줄을 인쇄 할 때만 빈 줄을 인쇄합니다.

i++비어 있지 않은 라인 카운터입니다.

!(i % 2)방법은 원하는 출력 방식으로 두 개의 연속 된 비어 있지 않은 행을 인쇄하기 위해 사용됩니다. 즉, 2의 배수가 발견 될 때마다 modulo명령문 !(i % 2)은 1이되고, 두 개의 비어 있지 않은 행의 연결이 종료됩니다.


내 잘못이야! 죄송합니다. 나는 그의 모든 질문과 원하는 결과를 읽지 못했습니다. 회신이 수정되었습니다. 감사. :-)
Marcelo Augusto 2016 년

0

Ex 모드에서 Vim을 사용할 수 있습니다 :

ex -sc v/./d -cx b.csv
  1. v/./ 빈 줄 찾기

  2. d 지우다

  3. x 저장하고 닫습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.