표준 입력의 행 그룹에 명령 적용

표준 입력의 행 그룹에 명령 적용

유닉스 패키지datamash다중 집계 작업을 지원하는 애플리케이션그룹줄 수를 입력하세요. 예를 들어 1 은 다음과 같이 datamash열 1의 각 값에 대한 열 2의 합계를 계산하는 데 사용됩니다.

$ cat example.csv
1,10
1,5
2,9
2,11
$ datamash -t, -g 1 sum 2 < example.csv
1,15
2,20

지원되는 기능 datamash도 매우 넓지만 ( , , , , 등 sum포함 ) 확장이 불가능합니다. AFAICT. IOW에서는 사용자가 자신의 요약 기능을 제공할 수 있는 메커니즘이 지원되지 않습니다.meanstddevmedianiqrminmaxdatamash

내 질문은 다음과 같습니다. 일반적으로 zsh2 에서 이러한 종류의 명령별 그룹 응용 프로그램을 어떻게 구현할 수 있습니까?


아래에서는 문제를 더 정확하게 설명하려고 합니다. (정확한 시도로 인해 질문을 이해할 수 없게 되지 않기를 바랍니다.)

먼저, foo이것이 다음 구조를 사용하여 stdout 라인으로 전송된 (복합 가능) 명령을 나타낸다고 가정합니다.

분할기 페이로드 i j

...어디, "그룹 인덱스"는 정수입니다.분할기상수 구분 기호 시퀀스(예: ,, 또는 $'\t')입니다.페이로드 i j임의의 텍스트입니다(종료 문자 포함). 또한 그룹 인덱스를 가정하면범위는 1부터질소, 이 출력의 행은 그룹 인덱스에 따라 정렬됩니다.

모든 정수에 대해 1 ≤ 케이 ≤ 질소,허락하다"케이"그룹 -"은 조각으로 구성된 콘텐츠를 나타냅니다.페이 로드 kjfoo그룹 인덱스가 있는 모든 행( 의 출력)케이.

다음으로, 이것이 barstdin에서 행을 읽고 발행하는 (복합일 수도 있는) 명령을 나타낸다고 가정합니다.하나의 선표준 출력으로.

이제결과케이bar다음에 적용된 출력을 나타냅니다.케이-번째 그룹, X<bar>호출하는 쉘 구성을 표현해 보겠습니다 bar.

나는 기본적으로 X<bar>파이프를 만드는 구조물을 찾고 있습니다.

foo | X<bar>

양식의 stdout 라인으로 전송됩니다.

분할기 결과


편집하다:

가설분할기그렇다면 ,다음은 내 요구 사항을 충족하는 것 같습니다.

TMPFILE=$( mktemp )
SEPARATOR=,
LASTGROUPID=
foo | (cat; echo) | while IFS= read -r LINE
do
    GROUPID=${LINE%%$SEPARATOR*}
    if [[ $GROUPID != $LASTGROUPID ]]
    then
        if [[ -n $LASTGROUPID ]]
        then
            echo -n "$LASTGROUPID$SEPARATOR"
            cat $TMPFILE | bar
        fi
        LASTGROUPID=$GROUPID
        : > $TMPFILE
    fi
    PAYLOAD=${LINE#*$SEPARATOR}
    echo $PAYLOAD >> $TMPFILE
done
rm $TMPFILE

$TMPFILE기본적으로 이는 다음 그룹의 행을 수집 하는 데 사용됩니다 . (임시파일은 피하고 싶은데 어떻게 해야할지 모르겠습니다.)

bar이제 표현된 표현식을 매개 변수로 사용하고 위에 제공된 구문에서 이를 강력하게 사용할 수 있는 함수로 이를 구현하는 방법을 찾아야 합니다 .


1이datamash 예는 매뉴얼 페이지에 제공된 예를 수정한 것입니다 .

2 나는 일차적인 관심이 있지만 부차적인 관심도 가지고 있습니다 zsh.bash

답변1

나에게 이것은 쉘 작업처럼 보이지 않습니다. 나는 이렇게 할 것이다 perl... 비록 여기면 충분할 수도 있지만:pythonrubyawk

$ cat sum
paste -sd + - | bc
$ sort -t , -k 1,1 input | awk -F, -v cmd=./sum '
   function out() {printf "%s,", l;close(cmd)}
   NR>1 && $1 != l {out()}
   {print $2 | cmd; l=$1}
   END {if (NR) out()}'
1,15
2,20

답변2

당신이 찾고 있는 것이 무엇인지 알고 있다면: 샘플 세트에서 분포를 생성하는 것과 유사하지만 더 많은 누적 옵션이 있는 스크립트입니다. 나는 awk이것을 위해 스크립트를 작성했습니다.

https://drive.google.com/open?id=0B0Kg_QLltwbNU21zbHFMY1hnSjQ

이는 정확히 원하는 것이 아니지만 겹치는 부분이 커야 합니다. 첫째 - 인덱스는 정수일 뿐만 아니라 둘째 - 유일한 누적 방법은 합계입니다. 하지만 단순한 스크립트이기 때문에 C 프로그램보다 쉽게 ​​수정할 수 있습니다.

마지막으로 이러한 스크립트는 데이터 세트가 충분히 작은 경우에만 작동하며, 더 큰 데이터 세트의 경우에는 너무 느립니다! 따라서 보다 전문적인 패키지가 더 좋습니다( R등).

PS 추가 누산기를 추가하려면 +=사용자 정의 함수("monad")로 바꾸십시오.

관련 정보