我基本上想这样做:
tail -f trades.csv | csvtool readable -
我想使用 csvtool 以可读格式读取 CSV 文件,并且想继续观看它。
我认为该命令不起作用,因为tail -f
从不发出流结束信号,因此 csvtool 无限期地等待。当然,这个常见问题有解决方法吗?
谢谢
答案1
不存在“发出 EOF”这样的事情。 EOF 不是带外信号。 EOF 是指尝试读取时报告没有剩余数据可供读取。
如果将 的输出通过管道传输tail -f
到一个在开始发出输出之前读取整个输入的程序,则该程序在读取完整输入之前不会发出任何输出。由于tail -f
永远不会关闭其输出(因为它永远不会停止发出输出),因此只有在终止尾部进程后才会发生这种情况。
csvtool readable
读取所有输入行,然后确定每个单元格的宽度,计算每列中单元格的最大宽度,最后发出宽度一致的所有行和列。在所有输入都可用之前不可能执行此计算,因为最后一行可能是具有最宽单元格的一行。因此,在逻辑上不可能csvtool readable
以在读取所有输入之前开始发出输出的方式进行设计。
也许您不关心所有行具有相同的列宽。也许您只想要大部分宽度,如果出现更宽的行,宽度就会放大。这是合理的。但这不是 csvtool 提供的功能。
在许多情况下,“逐渐发出输出foo | bar
时不会立即发出输出foo
”是由于foo
.看关闭管道中的缓冲。但这不是这里发生的事情。对于不需要整个输入的 csvtool 子命令,输入来自缓冲其输出的程序,这可能是不同情况下的问题。
如果您只想将 CSV 中的逗号转换为某种列对齐方式,并且您愿意手动指定列宽,那么这里有一个两行:
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对于挑剔者:超出第一行的第一个单元格,这没有帮助。
答案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 行,通过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(/^^ <-["]>+ <( \" .+ \" )> <-["]>+ $$/)
注意:我尝试过 Raku 的Text::CSV
模块,看看它是否可以与 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,因此您可以直接输出列,或每行元素数等。例如,将最后一条语句替换say @rows[*-1]
为say @rows[*-1][2]
以接收第三列的连续输出。
请参阅下面的 URL 了解sep-char
、escape-char
、formula-handling
、binary
、strict
设置等。
https://raku.land/github:Tux/Text::CSV
https://github.com/Tux/CSV
https://raku.org
答案3
如果csvtool
需要EOF——你运气不好。
但如果问题出在管道缓冲上,那么以下两者之一可能会有所帮助:
$ unbuffer tail -f trades.csv | csvtool readable -
$ stdbuf -i0 -o0 -e0 tail -f trades.csv | csvtool readable -