파일의 줄을 반복하고 현재 줄에서 이전 줄을 뺍니다.

파일의 줄을 반복하고 현재 줄에서 이전 줄을 뺍니다.

숫자가 포함된 파일이 있습니다.

$ cat file.dat
0.092593
0.048631
0.027957
0.030699
0.026250
0.038156
0.011823
0.013284
0.024529
0.022498
0.013217
0.007105
0.018916
0.014079

현재 줄과 이전 줄의 차이점을 포함하는 새 파일을 만들고 싶습니다. 예상되는 출력은 다음과 같아야 합니다.

$ cat newfile.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837

간단할 것 같아서 이 코드로 시작했습니다.

f="myfile.dat"    
while read line; do
    curr=$line
    prev=

    bc <<< "$line - $prev" >> newfile.dat
done < $f

그러나 나는 파일의 이전 줄에 액세스하는 방법을 모른다는 것을 곧 깨달았습니다. 첫 번째 줄을 읽을 때 빼기가 없어야 한다는 점도 고려해야 할 것 같습니다. 진행 방법에 대한 안내를 주시면 감사하겠습니다!

답변1

$ awk 'NR > 1 { print $0 - prev } { prev = $0 }' <file.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837

쉘 루프 호출 내에서 이 작업을 수행하는 것은 bc번거롭습니다. 위의 내용은 awk파일의 값을 하나씩 읽고 첫 번째 줄 이후의 모든 줄에 대해 설명하는 차이점을 인쇄하는 간단한 스크립트를 사용합니다.

NR > 1 { print $0 - prev }두 번째 줄 이상( NR지금까지 읽은 레코드 수, 기본적으로 "레코드"는 한 줄임)에 도달하면 첫 번째 블록은 조건부로 이 줄과 이전 줄의 차이를 인쇄합니다.

두 번째 블록 { prev = $0 }은 무조건 prev현재 행의 값으로 설정됩니다.

newfile.dat결과를 저장 하려면 출력을 리디렉션하세요 .

$ awk 'NR > 1 { print $0 - prev } { prev = $0 }' <file.dat >newfile.dat

관련된:


누군가 bc루프 호출이 느리다고 언급했습니다. 다음은 쉘 루프에서 데이터를 읽는 동안 단일 호출을 사용하여 산술을 수행하는 방법입니다. bc(저는 실제로 이 방법으로 문제를 해결하는 것을 권장하지 않습니다. co에 관심이 있는 모든 사람을 위해 여기에 표시하고 있습니다.) - 프로세스는 다음과 같습니다 bash.

#!/bin/bash

coproc bc

{
    read prev

    while read number; do
        printf '%f - %f\n' "$number" "$prev" >&"${COPROC[1]}"
        prev=$number

        read -u "${COPROC[0]}" result
        printf '%f\n' "$result"
    done
} <file.dat >newfile.dat

kill "$COPROC_PID"

의 값 ${COPROC[1]}은 표준 입력 파일 설명자 이지만 표준 출력 파일 설명자는 아닙니다bc .${COPROC[0]}bc

답변2

쉘 루프 없이 몇 가지 간단한 GNU 유틸리티 사용:

paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc

여기서의 아이디어는 입력 파일을 두 개의 열로 복사하고 두 번째 열을 1행씩 오프셋하고 열을 -구분 기호로 붙여넣는 것입니다. 필요한 오프셋을 달성하기 위해 각각 첫 번째 열의 마지막 행과 두 번째 열의 첫 번째 행을 자르는 데 사용됩니다 head. tail결과 목록은 bc평가에 필요한 산술 차이 목록으로 연결됩니다.

온라인으로 사용해 보세요.


또는 원하는 경우 sed다음을 수행할 수 있습니다.

sed '1{s/$/-\\/;p;d};${p;d};s/.*/&\n&-\\/' file.dat | bc

-\이렇게 하면 각 행이 복사되어 각 행의 두 번째 버전 끝에 삽입됩니다 . 첫 번째 줄과 마지막 줄은 필요한 표현식을 생성하기 위해 다르게 처리됩니다. sed의 출력은 다음과 같습니다.

a-\
b
b-\
c
c-\
d

이는 평가할 수 있는 유효한 산술 차이이기도 합니다 bc. bc줄 하나 걸러서 끝에 있는 줄 연속 백슬래시는 인식되지 않습니다 .

온라인으로 사용해 보세요.

답변3

쉘 스크립트를 강제로 작동시키려는 경우 일부 초기화가 누락된 것입니다.

f=myfile.dat
prev=0
while read line; do
    bc <<< "$line - $prev"
    prev=$line
done < $f > newfile.dat

...또한 일부 I/O를 절약하기 위해 루프 외부로 리디렉션을 이동했습니다.

bc솔루션은 선행 0을 인쇄하지 않지만이상한 솔루션하다.

답변4

나는 배열을 사용합니다. 나는 그것을 모든 것에 사용합니다. 매뉴얼 페이지를 광범위하게 연구하지 않고 awk와 sed가 어떻게 작동하는지 기억이 나지 않습니다. 이것이 내가 하는 방법이다.

f=( $(< file.dat) )
for ((num=1;num<=${#f[@]};num++))
do
    echo $(bc <<< ${f[$num]}-${f[(($num-1))]})>>differences.dat
done

이것이 내가 이해하는 방법입니다. 그것은 다른 답변 중 일부의 불쾌한 특성을 가지고 있습니다. 즉, bc를 계속해서 반복하고 호출하는 것입니다. 그러나 sed 및 awk를 사용한 답변처럼 파일을 한 번만 읽습니다.

관련 정보