EOF를 내보내지 않는 "tail -f" 문제를 해결하고 "csvtool"과 같은 도구를 사용하여 작동하게 만드는 방법은 무엇입니까?

EOF를 내보내지 않는 "tail -f" 문제를 해결하고 "csvtool"과 같은 도구를 사용하여 작동하게 만드는 방법은 무엇입니까?

나는 기본적으로 이렇게 하고 싶습니다:

tail -f trades.csv | csvtool readable -

csvtool을 사용하여 읽을 수 있는 형식의 CSV 파일을 읽고 싶고 계속해서 보고 싶습니다.

tail -fend-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 데이터를 처리할 수 있습니다. 그러나 CSVRaku로 작성된 실제 파서가 이 아키텍처를 활용할 수 있는지 여부는 불분명합니다 .

다음 코드는 행(행)을 쉼표로 구분하려는 경우에 작동합니다. 그것은react/wheneverRaku의 블록("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이므로 열이나 행당 요소 수 등을 직접 출력할 수 있습니다. 예를 들어 세 번째 열에 대한 연속 출력을 받으려면 마지막 문을 say @rows[*-1]로 바꾸세요.say @rows[*-1][2]

sep-char, escape-char, , 설정 등에 대한 자세한 내용은 아래 URL을 참조하세요 formula-handling.binarystrict

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 -

관련 정보