空の行を削除するためにテキストファイルをフィルタリングする良い方法は何ですか?


11

空の行がたくさんある(Macの).csvファイルがあります。例:

"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"

ライナーが1つあるはずですが、awkやsedはわかりません。ヒントは大歓迎です!


1
そのサンプルによると、フィールドから埋め込まれた改行を実際に削除する必要があります。あれは正しいですか?言い換えれば、6つの入力ラインがあり、2つの出力ラインである必要がありますか?
manatwork 2012年

はい、まさにそれを私が取り除こうとしているものです:引用符で囲まれた文字列の中に埋め込まれた改行。
ピトサラス

したがって、必要なのは引用符内の改行を削除するものです。複数行の正規表現が必要なため、少し複雑になります。
tongpu

回答:


11

-vこれを行うには、grepの(一致の反転)モードを使用できます。

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

シェルのリダイレクトのしくみのため、これらは異なるファイルである必要があることに注意してください。入力ファイルが読み取られる前に、出力ファイルが開かれます(そして空にされます)。moreutils(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

@pitosalasそれらはおそらく空行ではありません。それをegrep -v '^[[:space:]]*$'...に変更してみてください
。grep-

動作しませんでした。二重引用符の束を削除して混乱させた...
pitosalas

@pitosalas二重引用符を削除する方法がわかりません。空白のみを削除できる必要があります。そして、確かに、あなたが投稿したサンプルデータでテストすると、それが行われます...
derobert

@pitosalasは、これらのコマンドのいずれかが(iconv -f utf16le file.csv | headiconv -f utf16be file.csv | head
意味不明

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 +))にはバグがあり、その場合、ファイルは長さがゼロに切り捨てられているようです。

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

そのバグを回避するようですが、今では、sedコマンドよりもはるかに複雑です。


回答を1つの適切にフォーマットされたエントリにまとめ、各ソリューションをいつ使用するかについてのクイックガイドを用意してください。さまざまな問題へのさまざまなアプローチがすべて浮かび上がる答えの中で混乱しているため、この質問を読むのは少し厄介です。
Caleb

@Caleb、それはすべて非常に不明確な質問に要約されます。したがって、すべての人の答えはすべて、質問の異なる解釈に対するものです。それぞれの回答について、私はそれがどのような質問に答えようとしているのかを言おうとしました。
ステファンChazelas

Just FYI:awk '/./' file 1<>; fileうまくいったことを試しました。私には、それよりもさらに明確ですsed '/./!d'
グレブネーク2014年

5

以下がそのPerl一行です。

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

編集:以下のruakhのコメントに基づいてコードを改善しました。


1
またはperl -ni -e '/./ and print' yourfile
derobert

1
@peterph $はアンカー(つまり、幅がゼロ)なので、改行を除外します。余分なスペースについては、正規表現に `$ \`を挿入しようと/xは思わなかったのがこのためですPerl
Joseph R.

1
$を持っている場合、は必要ありません\n。(または\n\s*とがあるので、は必要ありませんが、改行が削除されていることがより明確$になると思いs/^\s*\n//ます。)また、/m; も必要ありません。このコマンドには影響しません。と$スペースを取り除くと、は必要なくなります/x
ruakh

1
@JosephR .: \n自体削除できます。できないのは、両方を削除することです。だから、あなたが説明する問題がありますが、とのために大丈夫です。(私の意味がわかりますか?)$ \ns/^\s*//s/^\s*$//\s*$
ruakh

1
@JosephR .:何が起こるかは、改行の前に一致する$ 可能性があります(/mフラグが有効であるか、改行が文字列の最後の文字、またはその両方である場合)、または文字列の末尾と一致することできます。たとえば、"abc" =~ m/^abc$/trueです。の場合\s*$\s*は貪欲で改行を食い尽くし、$は文字列の終わりに一致します。(s/^\s*\n//とにかく、私はもっとはっきりしていると思うので、あなたの答えは今のようにうまく
いき

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'

また、perlの-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でできること:

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

また、perlの-iフラグを使用して、所定の場所でファイルを編集することもできます。

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

0

で空行を削除するより短い方法がありますAWK

awk 'NF' file

しかし、必要な出力を得るには、単純な1つのライナーが必要です。

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

説明

AWK空の行は、行/レコードにフィールドがないこと、つまりNF(フィールド数)変数がゼロであることを意味します。上記の1つのライナーNF > 0は、空の行を除くすべての行を印刷する場合にのみ実行されます。

i++非空行カウンタです。

!(i % 2)であるあなたの希望する出力の方法で、二つの連続非空行を印刷するために使用され、2の倍数が発見されるたびに、modulo!(i % 2)利回り1は、二つの非空行の連結を終了するもの。


悪い!ごめんなさい。私は彼の質問全体と望ましい出力を読みませんでした。返信が修正されました。ありがとう。:-)
マルセロアウグスト

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.