거의 2000줄의 입력 파일이 있습니다. 계산을 해서 세 번째 열에 인쇄해야 해요.
입력 파일과 관련된 작업의 예:
n ID1_1 n/(n+k)
k ID1_2
입력 파일:
10 ID1_1
20 ID1_2
1 ID3_1
9 ID3_2
20 ID20_1
15 ID2_1
300 ID2_2
예상 출력:
10 ID1_1 0.33
20 ID1_2
200 ID3_1 0.11
9 ID3_2
20 ID20_1 /*I would just leave it like that*/
15 ID2_1 0.047
300 ID2_2
간단한 해결책이 있나요? 감사해요.
답변1
표시된 입력을 고려하면 다음이 작동합니다.
<infile sed -e '$!N;2i\' -e '3k
s|\(\(.* *\).*_1\)\n\(\(.* *\).*_2\)$|[\1 ]P\2d\4+/p[\3]pc|;t
s|^[ _ID0-9]*|[&]pc|;P;D' | dc
나를 위해 그것은 인쇄됩니다 ...
10 ID1_1 .333
20 ID1_2
1 ID3_1 .100
9 ID3_2
20 ID20_1
15 ID2_1 .047
300 ID2_2
... dc
정밀도를 3으로 설정했는데 정밀도가 10이기 때문입니다...
10 ID1_1 .3333333333
20 ID1_2
1 ID3_1 .1000000000
9 ID3_2
20 ID20_1
15 ID2_1 .0476190476
300 ID2_2
출력 정밀도 외에도 귀하의 정밀도와도 다릅니다.예상 출력세 번째 줄에 - 하지만 이것은 질문의 오타 때문인 것 같습니다.
어쨌든, 이를 이해하려면 먼저 출력을 두 가지 형식으로 구문 분석해야 한다는 점을 고려해야 합니다. dc
다음 의 ewline 없이 a를 인쇄 dc
하거나 숫자 또는 1과 함께 a를 인쇄합니다. 매크로 로 실행하는 것 외에는 문자열로 아무 것도 할 수 없습니다 . 하지만 수치를 보면 매우 능력이 뛰어납니다.P
[string]
\n
p
[string]
x
dc
따라서 현재 줄이 마지막 줄이면 sed
먼저 $!N
현재 줄에 추가 줄을 추가합니다. 두 번째 줄에서는 stdout에 문자열을 삽입합니다. 이는 정밀도를 3으로 설정하는 명령입니다.!
$
i
3k
dc
그런 다음 교체하려고합니다.
s|\(\(.* *\).*_1\)\n\(\(.* *\).*_2\)$|[\1 ]P\2d\4+/p[\3]pc|
_1
이는 패턴 공간에 현재 적어도 하나의 공백이 포함되어 있는 경우에만 성공합니다. 어떤 지점에서는 바로 뒤에 줄눈 문자가 오고 \n
, 어떤 지점에서는 그 뒤에 적어도 하나의 공백이 오고, 어떤 지점에서는 _2
바로 뒤에 $
끝이 옵니다. 패턴 공간의
이는 위의 대체가 다음과 같은 라인 쌍에만 영향을 미친다는 것을 의미합니다.
...ID_1
...ID_2
...다른 사람도 아니고요. 영향을 미치면 내용을 사용 가능한 dc
스크립트로 변환합니다. 다음으로 t
교체가 성공했는지 확인하고 성공하면 스크립트에서 분기하여 교체 결과를 인쇄하고 더 이상 sed
명령을 실행하지 않습니다. 표준 출력을 표준 입력으로 dc
사용하므로 예를 들어 처음 두 줄을 다음과 같이 변경합니다.sed
sed
[ 10 ID_1 ]P10d20+/p[ 20 ID_2]pc
... dc
그런 다음 해당 입력을 다음과 같이 처리합니다.
[ 10 ID_1 ]
- 대괄호 사이의 문자열을 스택의 맨 위로 밀어 넣습니다.(이렇게 하면 이미 스택에 있는 모든 항목이 하나 아래로 푸시됩니다.)P
P
-뒤에 줄줄이 없이 스택의 상단을 인쇄\n
하고 팝합니다.(이렇게 하면 아래 스택의 모든 값이 1씩 증가합니다.)10
- 숫자 10을 스택 맨 위로 밀어 넣습니다.d
d
- 스택의 상단을 복사합니다.20
- 숫자 20을 스택 맨 위로 밀어 넣습니다.+
- 스택 상단에 2cd를 추가하고 스택 상단에 2cd를 추가합니다.(두 개를 동시에 터뜨림)그리고 결과를 스택의 맨 위로 밀어넣습니다./
- 스택의 맨 위에서 2cd를 나눕니다.(이제 우리는d
복사합니다10
)스택의 꼭대기에서(우리의10 20 +
결과) (두 개를 동시에 터뜨림)그리고 결과를 스택의 맨 위로 밀어넣습니다.p
p
- 스택의 상단을 인쇄합니다.(튀기지 않고)그 뒤에는 줄줄이 표시됩니다\n
.[ 20 ID_2]
- 문자열을 스택의 맨 위로 밀어 넣습니다.p
p
- 스택의 상단을 인쇄합니다.(다시 한번 말하지만 터뜨리지 마세요)그 뒤에는\n
Ewline 이 따른다c
c
- 스택을 이해하라
따라서 dc
다음을 인쇄하세요.
10 ID1_1 .333
20 ID1_2
그러나 sed
이미 설명한 것처럼 성공적인 일치가 없고 패턴 공간이 변경되면 처리할 다른 라인이 남습니다. 이 경우 sed
명령을 추가하여 와 사이에 첫 번째 시퀀스를 삽입할 수도 있습니다. 그런 다음 패턴 공간에서 처음으로 나타나는 ewline까지 패턴 공간을 인쇄한 다음 나머지 부분부터 시작하기 전에 동일한 내용을 삭제합니다. 따라서 전체적으로 한 줄의 예측이 수행되고 작업 스크립트는 항상 인쇄됩니다.[ ID_0-9]*
[
]
pc
P
\n
D
sed
dc
dc
이는 전체 파일이 스트림에서 처리됨을 의미합니다. ` dc
및 sed
` 모두 처리되는 대로 출력을 제공하기 때문입니다. 이렇게 하면 입력이 질문의 예와 유사하다면 동일한 방식으로 200만 개의 행을 쉽게 처리하거나 실시간으로 로그 파일을 처리할 수 있습니다.
답변2
파이썬으로.
#!/usr/bin/python3
import re
import sys
fil = sys.argv[1]
with open(fil) as f:
m = re.split(r'[\n\r]+(?= *\d+\s+ID\d+_1)', f.read())
l = []
for i in m:
l.append(re.sub(r'(?s)^(\s*(\d+)\s+([^_]+)_1)([\n\r]+\s*(\d+)\s+\3_2)$', \
lambda m: m.group(1) + " "+ str(float(m.group(2))/(float(m.group(2))+float(m.group(5)))) + m.group(4),i))
print('\n'.join(l), end = "")
위의 스크립트를 다른 이름으로 저장 script.py
한 후 실행해 보세요.
python3 script.py inputfile
예:
$ python3 f.py file
10 ID1_1 0.3333333333333333
20 ID1_2
1 ID3_1 0.1
9 ID3_2
20 ID20_1
15 ID2_1 0.047619047619047616
300 ID2_2
답변3
awk
다음 명령 하나로 모든 작업을 수행 할 수 있습니다 .
$ awk '{if(NR%2){n=$1;last=$0;}else{print last,n/(n+$1)"\n"$0}}' file
10 ID1_1 0.333333
20 ID1_2
1 ID3_1 0.1
9 ID3_2
15 ID2_1 0.047619
300 ID2_2
아이디어는 단순히 현재 행이 짝수인지 확인하는 것입니다. i) 그렇다면 last
필요한 계산과 함께 이전 행( )을 인쇄하고, ii) 그렇지 않으면 현재 행을 last
첫 번째 필드 로 저장합니다 n
.
다음을 사용하여 인쇄되는 소수 자릿수를 제어할 수 있습니다 printf
.
$ awk '{if(NR%2){n=$1;last=$0;}else{printf "%s %.2f\n%s\n",last,n/(n+$1),$0}}' file
10 ID1_1 0.33
20 ID1_2
1 ID3_1 0.10
9 ID3_2
15 ID2_1 0.05
300 ID2_2
Perl에도 동일한 기본 내용이 존재합니다.
$ perl -lane 'if($.%2){$n=$F[0];$last=$_;}
else{printf "%s %.2f\n%s\n",$last,$n/($n+$F[0]),$_}' file
10 ID1_1 0.33
20 ID1_2
1 ID3_1 0.10
9 ID3_2
15 ID2_1 0.05
300 ID2_2
답변4
OP 편집 후(추가된 용어 참조):
awk '
/ID.*_1/{
n=$1
idx=$2
sub("_1","_2",idx)
printf s"%s",$0
s="\n"}
$2==idx{
printf " %.2f\n%s",n/(n+$1),$0}
END{
print""}' file