해결 방법을 찾아보았지만 이렇게 특정한 문제(구글에 입력해야 할 단어가 너무 많음)에 대한 해결 방법을 찾는 것이 조금 어렵습니다.
그래서 다음과 같은 데이터가 포함된 파일이 있습니다(관련 없는 데이터는 생략됨).
... ... 2014년 1월 1일 ... ... ... ... ... 2014년 1월 2일 ... ... ... (...) ... ... 2014년 3월 1일 ... ... ... (...)
데이터가 날짜별로 정렬되어 있다고 가정할 수 있습니다. 그래서 제가 하고 싶었던 것 중 하나가 월의 범위에 맞는 라인을 캡쳐하는 것이었습니다. 예를 들어 범위가 2월부터 4월까지인 경우 월 열에 Feb
, 및 가 포함된 모든 행을 가져오고 싶습니다 .Mar
Apr
문제를 명시하지 않고 요청을 약간 추상화하기 위해 특정 패턴과 일치하는 첫 번째 행을 가져오고 다른 패턴이 마지막으로 나타날 때까지 해당 지점부터 모든 행을 캡처하고 싶습니다. 특정 패턴이 함께 그룹화됩니다).
또는 를 사용 하여 유사한 문제에 대한 몇 가지 해결책을 찾았습니다 grep
. 이 상황에서는 어느 것이 가장 좋은지 잘 모르겠습니다.sed
awk
이것은 모두 bash 스크립트에서 수행되므로 모든 월 "코드"가 포함된 배열 [ Jan
, Feb
, Mar
, ...]을 갖고 내가 원하는 범위에 있는지 어떻게든 확인하려고 생각했습니다. 이 문제에 대한 더 우아한 해결책이 될 것입니다.
편집: @jasonwryan 글쎄, 실제로 스크립트에 범위를 지정했기 때문에 './script.sh --month "Jan, Apr"'는 데이터 파일을 월별로 정렬한 다음 모든 범위를 grep할 수 있어야 합니다(이 경우 1~4월). 따라서 awk '/Feb|Apr|May/'는 이 경우 작동하지만 2월부터 11월까지를 원하는 경우에는 다릅니다(awk '/Feb|Mar|Apr|May|Jun|Jul|Aug |Sept| 11/' 파일). 따라서 임의의 범위를 기반으로 자동화하는 것은 어렵습니다. 또한 한 달에 한 번 이상(매일 가능) 대기열이 있어야 합니다. 지정하는 것을 잊었습니다.
답변1
mrng(){ sed "$(set -f;unset IFS rng l;n='
';[ -n "$ZSH_VERSION" ] && emulate sh
prng() for m do rng=${r%%"$m"*}${r##*"$m"} _l=$((_l+1))
printf "\n\n%s\n/$pat/{\n\t:$l.$_l\n\tn" $m
printf "\n\n%s\n\t/$pat/b$l.$_l.0" $rng
printf "\n\tb$l.$_l\n\t:$l.$_l.0\n}"
done
pat=$( printf %s "${1:-%m}$n"| sed -n 's/%/&&/g;l'|
sed ":n$n\$!N;s/\\\\\n//;tn${n}s/\$$//"); shift
r=$( locale -c LC_TIME|sed '4!d;y/;/ /')
for m do case $m in (-) rng=$r ;;
(-*) rng=${r%%"${m#-}"*}${m#-} ;;
(*-) rng=${m%-}${r##*"${m%-}"} ;;
(*-*) rng=${m%%-*}${r##*"${m%%-*}"} ;
case $rng in (*${m##*-}*)
rng=${rng%%"${m##*-}"*}${m##*-} ;;(*)
rng=$rng\ ${r%%"${m##*-}"*}${m##*-};;esac
;;esac; : $((l+=1))
prng ${rng:="$m"}; unset rng
done| sed " 1d;s/.*\(...\)\(\n\)\(.*[^%]\(%%\)*\)%m/\2\1\2\3\1/
/./!{N;N$n};/\n/D"
);d"
}
이것은 셸 함수입니다. 이 방식으로 호출하려면 이를 셸 스크립트에 적용하거나 현재 셸에서 평가해야 합니다. 다음과 같이 호출할 수 있습니다.
mrng "$pat" Jan-Mar Jun Sep-Nov <infile
-
또한 다음 과 같은 개방형 범위도 허용합니다.모두아니면 Mar-
3월부터 12월까지. 주장은 그렇지 않다가지다범위 지정 - 위에서 언급한 대로 Jun
그게 전부입니다.
그러나 실제로는 월 이름을 전혀 해석하지 않으며 locale
유틸리티에서 수집합니다.(이것은 종속성입니다)그리고 현재 로캘에서 3자로 된 월 이름을 사용하여 작동합니다.
실제로는 거의 모든 범위에서 서라운드 범위를 수행할 수 있습니다.하다서라운드, 또는 아마도 더 나은 표현으로 어쨌든 축적하십시오.
첫 번째 인수는 sed
호환 가능한 BRE 스키마일 것으로 기대합니다. 예외는 월 이름이 나올 것으로 예상되는 곳마다 사용해야 한다는 것입니다 %m
. s를 여러 개 삽입할 수도 있습니다 %m
. Mar...Mar
-와 같은 줄만 일치시키려는 경우에도 이 작업을 수행할 수 있습니다 Jun...Jun
. 어쩌면 이것은 별로 유용하지 않을 수도 있지만 아마도...?
복잡해 보이지만 그 중 절반 이상이 인수 구문 분석을 위한 것입니다. sed
결국 상대적으로 간단합니다. 예를 들어, 이렇게 하면:
mrng %m Dec-Jan
sed
... 다음과 같은 스크립트 가 생성됩니다 .
/Dec/{
:1.1
n
/Jan/b1.1.0
/Feb/b1.1.0
/Mar/b1.1.0
/Apr/b1.1.0
/May/b1.1.0
/Jun/b1.1.0
/Jul/b1.1.0
/Aug/b1.1.0
/Sep/b1.1.0
/Oct/b1.1.0
/Nov/b1.1.0
b1.1
:1.1.0
}
/Jan/{
:1.2
n
/Feb/b1.2.0
/Mar/b1.2.0
/Apr/b1.2.0
/May/b1.2.0
/Jun/b1.2.0
/Jul/b1.2.0
/Aug/b1.2.0
/Sep/b1.2.0
/Oct/b1.2.0
/Nov/b1.2.0
/Dec/b1.2.0
b1.2
:1.2.0
};d
...결국 많은 코드가 생성되고 대부분의 경우 평가되지 않습니다. 일반적인 라인에서는 Dec와 일치하는지 확인하고, 그렇지 않으면 Jan과 일치하는지 확인하고, 그렇지 않으면 출력에서 제거합니다.
그러나 이러한 패턴 중 하나와 일치하면 간단한 분기 루프가 시작됩니다. 따라서 위의 예에서 라인이 Dec와 일치하면 인쇄되고 n
외부 입력 라인으로 덮어쓰게 됩니다. 새 행이 임의의 달과 일치하는 경우하지만12월, sed
b
목초지 라벨 :1.1.0
- 이는 라인이 아직 평가되지 않았음을 의미합니다 Jan
. 유사하게 처리되지만 어떤 달에도 평가되지 않습니다.앞으로12월을 제외하고 일치하는 달이 없으면 라벨 sed
b
위로 이동하여 라인을 인쇄하고 확장자를 당깁니다.:1.1
n
이렇게 하면 범위의 각 달에 대해 -
위와 유사한 함수(각각 고유한 레이블이 있음)가 생성됩니다 . :
이는 명령줄 인수가 누적 효과를 갖는다는 것을 의미합니다. 몇 가지 예:
printf %s\\n 'not a month' May 'not a month' 'also not a month' Apr |
m_rng %m Apr May
위의 내용은 다음과 같습니다.
May
not a month
also not a month
입력에서는 May
앞에 오고 명령줄에서는 뒤에 오기 때문 Apr
입니다 . Apr
그러나 이는 다소 조잡한 경험적 방법입니다. 입력은 명령줄 인수 순서대로 처리되지만 전체 주기가 완료되면 처리가 다시 시작되므로...
printf %s\\n 'not a month' May 'not a month' 'also not a month' Jun Apr |
m_rng %m Apr May
...인쇄...
May
not a month
also not a month
Apr
루프가 에서 중단되기 때문에 Jun
해당 줄은 제거되고 다음 입력 줄인 에서 처리가 다시 맨 위에서 시작됩니다 Apr
.
어쨌든 패턴에는 다음을 사용해야 합니다.
mrng '^\([^ ]\{1,\} *\)\{3\}%m' [month args]