私は基本的にこれをしたいと思います:
tail -f trades.csv | csvtool readable -
csvtoolを使用して読み取ることができる形式のCSVファイルを読みたいと思っています。
tail -f
end-of-stream信号が決して放出されないため、このコマンドは機能しないため、csvtoolは無期限に待機します。確かに、この一般的な問題に対する解決策はありますか?
ありがとう
答え1
「EOF放出」のようなものはありません。 EOFは帯域外信号ではありません。 EOFは、読み取ろうとしたときに読み取るデータが残っていないと報告する場合です。
tail -f
出力のエクスポートを開始する前に入力全体を読み取るプログラムに出力がパイプされている場合、プログラムは入力全体を読み取るまで出力をエクスポートしません。出力が閉じないためtail -f
(出力の放出を停止しないため)、これはテールプロセスが終了した後にのみ発生します。
csvtool readable
すべての入力行を読み取り、各セルの幅を決定し、各列のセルの最大幅を計算し、最後に一貫した幅ですべての行と列をエクスポートします。すべての入力が利用可能になるまでこの計算を実行することはできません。なぜなら、最後の行がおそらく最も広いセルを含む行であるからです。したがって、csvtool readable
すべての入力を読み取る前に出力を放出し始めるように設計することは論理的に不可能です。
たぶん、列の幅が同じすべての行に興味がない可能性があります。たぶん、ほとんどの幅が欲しいかもしれませんが、より広い行が現れると幅が拡大します。これは合理的です。しかし、これはcsvtoolが提供する機能ではありません。
多くの場合、「出力はfoo | bar
すぐには放出されず、徐々に放出されますfoo
」が発生しますfoo
。パイプラインでバッファリングをオフにする。しかし、ここで起こっていることはそうではありません。出力をバッファリングするプログラムの完全な入力を必要としないcsvtoolサブコマンドの場合、これはさまざまな状況で問題になる可能性があります。
CSVのコンマをいくつかの列の並べ替えに変換し、列の幅を手動で指定したい場合は、以下は2行の並べ替えです。
tail -f … | python3 -u -c 'import csv, sys
for row in csv.reader(sys.stdin): print("\t".join(row))' | expand -t 11,13,17
expand
ほとんどの端末とエディタで使用されている8つの列ごとにデフォルトのタブが満たされている場合は、この手順は不要です。
1 nitpickersの場合:最初の行の最初のセルを超えることは役に立ちません。
答え2
使用幸せ(以前のPerl_6)
Rakuは、同時、非同期、並列の「CAP」プログラミングアーキテクチャを実装しています。 「CAP」プログラミングのいくつかの側面は、データストリーミングに役立ちます。 RakuのJSON::Stream
パッケージはストリーミングJSONデータを処理できます。しかし、CSV
Rakuで書かれた実際のパーサーがこのアーキテクチャを利用できるかどうかは不明です。
次のコードは、行(行)をコンマで区切る場合に機能します。それreact
/whenever
Rakuのブロック(「CAP」アーキテクチャ)。以下は、埋め込まれた改行文字、二重引用符の中に含まれるカンマを処理しませんが、開始です(でもテスト済み/var/log/system.log
)。
~$ tail -n2 -f MS.csv | raku -e 'react { \
whenever Supply( $*IN.lines ) -> $ln { \
.split(",").raku.match(/^^ <-["]>+ <( \" .+ \" )> <-["]>+ $$/).put for $ln } };'
入力サンプル(https://www.microsoft.com/en-us/download/details.aspx?id=45485):
User Name,First Name,Last Name,Display Name,Job Title,Department,Office Number,Office Phone,Mobile Phone,Fax,Address,City,State or Province,ZIP or Postal Code,Country or Region
[email protected],Chris,Green,Chris Green,IT Manager,Information Technology,123451,123-555-1211,123-555-6641,123-555-9821,1 Microsoft way,Redmond,Wa,98052,United States
[email protected],Ben,Andrews,Ben Andrews,IT Manager,Information Technology,123452,123-555-1212,123-555-6642,123-555-9822,1 Microsoft way,Redmond,Wa,98052,United States
[email protected],David,Longmuir,David Longmuir,IT Manager,Information Technology,123453,123-555-1213,123-555-6643,123-555-9823,1 Microsoft way,Redmond,Wa,98052,United States
[email protected],Cynthia,Carey,Cynthia Carey,IT Manager,Information Technology,123454,123-555-1214,123-555-6644,123-555-9824,1 Microsoft way,Redmond,Wa,98052,United States
[email protected],Melissa,MacBeth,Melissa MacBeth,IT Manager,Information Technology,123455,123-555-1215,123-555-6645,123-555-9825,1 Microsoft way,Redmond,Wa,98052,United States
出力例(最後の2行のみ処理済み、pass tail -n2 -f
):
"cynthia\@contoso.com", "Cynthia", "Carey", "Cynthia Carey", "IT Manager", "Information Technology", "123454", "123-555-1214", "123-555-6644", "123-555-9824", "1 Microsoft way", "Redmond", "Wa", "98052", "United States"
"melissa\@contoso.com", "Melissa", "MacBeth", "Melissa MacBeth", "IT Manager", "Information Technology", "123455", "123-555-1215", "123-555-6645", "123-555-9825", "1 Microsoft way", "Redmond", "Wa", "98052", "United States"
上記で引用されていない出力を受け取るには、単にを使用し、次へ.put
の中間呼び出しを削除します。
.raku.match(/^^ <-["]>+ <( \" .+ \" )> <-["]>+ $$/)
Text::CSV
注:Rakuモジュールと互換性があることを確認するために、Rakuモジュールを使用してみました。react
/whenever
ブロックですが、これまでは運がありません。私ができる最善は、ブロックを実装することでした。ブロックに入力while
のみを提供すると、tail
まともな解決策になります。コードは以下のように表示されます。
~$ tail -n2 -f MS.csv | raku -MText::CSV -e 'my @rows; \
my $csv = Text::CSV.new; \
while ($csv.getline($*IN)) -> $row { \
@rows.push: $row; say @rows[*-1].raku; };'
出力例:
$["cynthia\@contoso.com", "Cynthia", "Carey", "Cynthia Carey", "IT Manager", "Information Technology", "123454", "123-555-1214", "123-555-6644", "123-555-9824", "1 Microsoft way", "Redmond", "Wa", "98052", "United States"]
$["melissa\@contoso.com", "Melissa", "MacBeth", "Melissa MacBeth", "IT Manager", "Information Technology", "123455", "123-555-1215", "123-555-6645", "123-555-9825", "1 Microsoft way", "Redmond", "Wa", "98052", "United States"]
[上記の呼び出しを削除して引用符のない出力を取得する.raku
か、呼び出しを追加して二重引用符を保持し、行の先頭.match(/^^ <-["]>+ <( \" .+ \" )> <-["]>+ $$/)
/末尾から不要な文字を削除します。]
上記のコードは、@rows
ユーザーが何かをしたい場合に備えて、着信データを配列にプッシュします。何よりもText::CSV
真のCSVパーサーなので、CSV入力を検証できます。また、入力が検証されたCSVなので、列や行当たりの要素数などを直接出力できます。たとえば、3番目の列の連続出力を受け取るには、最後のステートメントをsay @rows[*-1]
に置き換えます。say @rows[*-1][2]
sep-char
、、、、escape-char
設定などの詳細については、下記のURLをご覧くださいformula-handling
。binary
strict
https://raku.land/github:Tux/Text::CSV
https://github.com/Tux/CSV
https://raku.org
答え3
もしcsvtool
必要EOF - あなたは幸運ではありません。
ただし、パイプのバッファリングに問題がある場合は、次の2つのいずれかが役に立ちます。
$ unbuffer tail -f trades.csv | csvtool readable -
$ stdbuf -i0 -o0 -e0 tail -f trades.csv | csvtool readable -