지금까지 돌아다닐 수 있었어요sed여러 줄에 걸쳐 앞으로/뒤로 보기와 같은 고급 기능이 있지만 다음을 달성하는 방법을 알고 싶습니다.sed예를 들어 내가 하는 방식이 다음과 같다고 느끼기 때문입니다.파이썬필요하지 않으며 필터 덕트 내부에서도 수행 가능지침.
들어오는 데이터를 제거하는 예는 다음과 같습니다.
1b41cf70 0
1cb8dd19 1
620f0b67 2
620f0b67 3
f35d35fe 4
3a6fb62a 5
620f0b67 6
620f0b67 7
620f0b67 8
b958a7ea 9
f35d35fe 10
f35d35fe 11
620f0b67 12
첫 번째 열은 항상 동일한 너비(단축된 해시 포함)이고 두 번째 열의 내용은 완전히 정렬되고 숫자이며 간격이 없습니다(따라서 더 긴 목록에 방향을 제공하는 경우를 제외하고는 필요하지 않을 수 있습니다).
원하는 출력은 다음과 같습니다(마지막 연속 발생의 색인을 추가 열에 넣습니다).
1b41cf70 0
1cb8dd19 1
620f0b67 2 3
f35d35fe 4
3a6fb62a 5
620f0b67 6 8
b958a7ea 9
f35d35fe 10 11
620f0b67 12
또는 집계된 중복 값 수(수학적 표현(덧셈))를 사용하는 것이 더 나은 방법입니다.앗하지만 내 실력이 더 나쁘기 때문에 이것은 다른 이상적인 결과를 설명하기 위한 것입니다.)
1b41cf70 0
1cb8dd19 1
620f0b67 2 +1
f35d35fe 4
3a6fb62a 5
620f0b67 6 +2
b958a7ea 9
f35d35fe 10 +1
620f0b67 12
SO 공간에서 찾은 유사하지만 다른 몇 가지 질문을 추적하려고 했지만 sed '$!N;/^\([^\ ]\+\)\ [0-9]\+\n\1\ /{P;d}' sampledata
인덱스가 3,7,11인 이유와 같이 솔루션으로 이어질 수 있는 더 간단한 부분이 무엇인지 머리를 감쌀 수 없습니다. 행을 자르기 위해 Not 8 대신 사용됩니다.
내 시스템에는 GNU sed 버전 4.8과 awk 버전 5.1.0이 설치되어 있으며 그 중 하나를 사용하여 이 작업을 수행하는 방법을 알고 싶습니다. 아니요, 이것은 숙제가 아니라 압축하고 비교해야 하는 중복성이 많은 긴 해시 목록입니다. ;)
답변1
원래 두 번째 열을 완전히 무시하면 이를 사용하여 uniq -c
연속 행에서 문자열이 반복되는 횟수를 계산할 수 있습니다.
두 필드의 출력을 사용하면 문자열이 여러 번 반복될 때마다 세 번째 필드를 만들 수 있습니다 uniq -c
(테이블에서 필드 발생 횟수 +x
에서 1을 뺀 값). x
그런 다음 처음 두 필드를 다시 정렬하고 인쇄합니다.
cut -d ' ' -f 1 file |
uniq -c |
awk '$1 > 1 { $3 = "+" $1 - 1 } { nr += $1; $1 = $2; $2 = nr - 1 - $3; print }'
이 nr
변수는 원본 파일의 줄 번호를 나타냅니다.
질문의 데이터 출력을 제공합니다.
1b41cf70 0
1cb8dd19 1
620f0b67 2 +1
f35d35fe 4
3a6fb62a 5
620f0b67 6 +2
b958a7ea 9
f35d35fe 10 +1
620f0b67 12
답변2
사용 awk
:
awk 'function prnt() { print buf, preV; preK=$1; preV=""; buf=$0 }
preK!=$1 { prnt(); next } { preV=$2 }
END { prnt() }' infile
산출:
1b41cf70 0
1cb8dd19 1
620f0b67 2 3
f35d35fe 4
3a6fb62a 5
620f0b67 6 8
b958a7ea 9
f35d35fe 10 11
620f0b67 12
awk 'function prnt() { print buf, (c?"+"c:""); preK=$1; c=0; buf=$0 }
preK!=$1 { prnt(); next } { c++ }
END { prnt() }' infile
산출:
1b41cf70 0
1cb8dd19 1
620f0b67 2 +1
f35d35fe 4
3a6fb62a 5
620f0b67 6 +2
b958a7ea 9
f35d35fe 10 +1
620f0b67 12
답변3
당신은 그것을 요청했습니다 sed
. 다음은 자신의 시도에 가까운 2가지 버전이지만 POSIX를 사용하는 것입니다.오히려
확장 정규식. 둘 다 패턴 공간에 최대 2줄을 유지합니다.
sed -E '
:Q
$!N
/^([^ ]+) ([0-9]+)( [0-9]+)?\n\1 ([0-9]+)$/{
s//\1 \2 \4/
bQ
}
P
D
' -- file
어디:
$!
마지막 줄에 개행 문자를 추가하고( ) 현재 줄에 다음 줄을 추가하지 않는 한 (N
)- 일치 표현식은
/…/
필드 1과 2를\1
및 로 캡처하고\2
가능한 마지막 인덱스는 이며\3
마지막 다음 행의 인덱스는 다음과 같습니다.\4
- 필드 1이 다음 줄에서 반복되면 전체 패턴 공간이 필드 1(해시), 필드 2(첫 번째 인덱스) 및 마지막 인덱스로 대체되어 스크립트 시작 부분으로 분기됩니다. 명령의 빈 정규식은 다음과
s
같습니다. 다시 적용됨 마지막 정규식 사용(in/…/
) - 그렇지 않으면 첫 번째 줄(
P;D;
)을 인쇄하고 삭제하고 루프를 다시 시작합니다.
산출:
1b41cf70 0
1cb8dd19 1
620f0b67 2 3
f35d35fe 4
3a6fb62a 5
620f0b67 6 8
b958a7ea 9
f35d35fe 10 11
620f0b67 12
대신에:
/^([^ ]+) ([0-9]+)( ([+]+))?\n\1 [0-9]+$/{
s//\1 \2 \4+/
출력은 다음과 같습니다.
1b41cf70 0
1cb8dd19 1
620f0b67 2 +
f35d35fe 4
3a6fb62a 5
620f0b67 6 ++
b958a7ea 9
f35d35fe 10 +
620f0b67 12
sed
계산을 좋아하지는 않지만 할 수는 있습니다.
sed
마지막으로 POSIX를 사용하는 스크립트에 대한 몇 가지 설명입니다.갈아 바수다에스
[]
이스케이프 문자를 제외하고 s 내의 문자를 이스케이프 하지 마십시오 . ,]
및 가능한 이스케이프 문자-
- BRE의 기호는
+
수량자가 아니라 일반적인 더하기 기호입니다. - 공백 문자를 이스케이프 처리할 필요가 없습니다.
}
이식성을 위해 편집 명령 목록을 끝내기 전에 세미콜론을 사용하십시오.- 이
d
명령은 첫 번째 개행 문자뿐만 아니라 전체 패턴 공간을 제거합니다.
답변4
빠르고 혼란스러운 여러 줄 찾기 및 바꾸기 솔루션(이번에는 Perl에서)
perl -0pe 's/(\w+) (\d+)(\n\1 (\d+))+/$1 $2 $4/g' file
해당 (gnu)sed 버전은 다음과 같습니다.
sed -rz 's/(\w+) ([0-9]+)(\n\1 ([0-9]+))+/\1 \2 \4/g' file
"+" 출력의 경우 몇 가지 추가 계산을 수행해야 합니다.
perl -0pe 's/(\w+) (\d+)(\v\1 (\d+))+/"$1 $2 +" . ($4-$2)/ge' file