줄 바꿈으로 구분된 정수 파일의 경우 연속된 정수를 검색한 다음 깨지지 않은 각 시퀀스의 연속된 정수 수와 각 시퀀스가 진행되는 방향(오름차순 또는 내림차순)을 나열하고 싶습니다.
내 파일은 다음과 같습니다.
2
3
4
5
1
7
4
5
6
3
2
1
내가 원하는 출력은 다음과 같습니다.
4^
3^
3v
첫 번째 문자는 연속된 숫자의 수를 나타내고, 두 번째 문자는 숫자가 오름차순인지 내림차순인지를 나타냅니다. Bash에서 이 작업을 수행할 수 있는 방법이 있나요?
답변1
Bash가 아니라 awk에서요. 대부분의 사람들은 bash/shell 스크립팅 공정한 게임을 고려합니다. 많은 사람. 적어도 그것이 나에게는 작동하는 방식입니다.
func printrun() {
if(run > 1) {
print run""dir
}
}
NR == 1 {
#print $1" first"
prev = $1
dir = "-"
run = 1
next
}
$1 == prev+1 && dir == "v" {
#print $1" up from down"
printrun()
prev = $1
dir = "^"
run = 2
next
}
$1 == prev+1 {
#print $1" up"
prev = $1
dir = "^"
run++
next
}
$1 == prev-1 && dir == "^" {
#print $1" down from up"
printrun()
prev = $1
dir = "v"
run = 2
next
}
$1 == prev-1 {
#print $1" down"
prev = $1
dir = "v"
run++
next
}
{
#print $1" else"
printrun()
prev = $1
dir = "-"
run = 1
}
END {
#print "end"
printrun()
}
코드를 압축하기 위해 if 및 else if 체인의 변형을 사용해 보았지만 이 변형이 가장 명확하고 읽기 쉽다는 것을 알았습니다.
다른 이름으로 저장run.awk
이렇게 달리다
$ awk -f run.awk inputfile
또는 파이프 입력
$ commandproducinginput | awk -f run.awk
설명하다:
awk는 대략 다음과 같이 작동합니다. 입력을 한 줄씩 읽습니다. 각 라인에 대해 조건이 참인 코드 블록을 실행합니다.
코드 블록은 중괄호 안에 들어 있습니다. 조건은 코드 블록 앞부분입니다.
condition { code block }
BEGIN
및 END
첫 번째 줄 앞과 마지막 줄 뒤에 각각 참인 특수 조건입니다. 이 코드에는 BEGIN
.only 가 없습니다 END
.
func
조건이 아닙니다. 대신 나중에 사용되는 함수 선언입니다.
첫 번째 블록의 조건은 입니다 NR == 1
. NR
실제로 줄 번호를 의미하는 레코드 번호입니다. 사실상 이는 블록이 첫 번째 줄에서 실행되고 다시는 실행되지 않음을 의미합니다. 이 블록에서는 변수를 일반 값으로 초기화합니다.
이 블록과 대부분의 다른 블록은 next
이 문으로 끝납니다. next
awk에게 이 루프를 포기하고 다음 줄을 로드하고 실행할 블록을 찾기 위해 다음 루프를 시작하도록 지시합니다. 그것을 제자리에 놓으면 next
체인이 있다면 효과적으로 큰 효과를 얻을 수 있습니다.
다음 블록의 조건은 이다 $1 == prev+1 && dir == "v"
. 이는 현재 숫자가 이전 숫자보다 하나 더 큰지, 이동 방향이 현재 아래로 향하고 있는지 여부를 테스트합니다. 둘 다 참이면 진행 중인 하향 실행을 인쇄하고 변수를 업데이트하여 새로운 상향 실행을 시작합니다. 그렇지 않은 경우 블록은 실행되지 않고 awk는 실행할 다음 블록을 찾습니다.
다음 조건과 블록은 유사합니다.
두 번째 블록( END
이 블록 앞의 블록)은 무조건 블록입니다. 이는 각 행에 대해 실행된다는 의미입니다. 이전 블록의 명령문 으로 인해 next
이전 블록이 실행되지 않은 경우에만 블록이 실행됩니다. 실제로 이 블록은 if else if 체인의 "else"입니다.
숫자가 연속적인 위 또는 아래가 아닌 경우 이 블록에 도달합니다. 따라서 이 블록의 코드는 실행 종료에 해당하는 변수를 설정합니다.
의사코드에서 코드는 다음과 같습니다.
if first line:
init vars and set run to none
else if now going up but was going down:
print ongoing run down and start a run up
else if now going up:
start or continue run up
else if now going down but was going up:
print ongoing run up and start a run down
else if now going down:
start or continue run down
else:
print ongoing run and set run to none
if end of input:
print ongoing run
답변2
awk 'function prnt(Xdir){ if (c)print c+1, Xdir; c=0 }
(pre+1==$0){ prev_dir=dir; dir="▲"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=$0; next }
(pre==$0+1){ prev_dir=dir; dir="▼"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=$0; next }
c{ prnt(dir) }
{ pre= $0}
END{ prnt(dir) }' infile
4 ▲
3 ▲
3 ▼