POSIX 매개변수 확장을 사용하여 변수에서 중복 문자열 패턴을 제거합니다.

POSIX 매개변수 확장을 사용하여 변수에서 중복 문자열 패턴을 제거합니다.

나는 사용하고 싶다2.6.2 매개변수 확장문자열에서 선행 문자를 제거했지만 "최대 접두사 패턴 제거"가 패턴을 자동으로 반복하지 않는다는 사실에 놀랐습니다.

$ x=aaaaabc
$ printf %s\\n "${x##a}"
aaaabc

보시다시피 첫 번째 항목만 a삭제되었습니다. 예상되는 출력은 , 또는 bc중 하나 입니다.x=bcx=abcx=aabcx=aaabcx=aaaabc

a의 시작 부분부터 최대한 제거하고 싶다면 패턴을 어떻게 작성해야 할지 고민 중입니다 $x. 많은 답변이 bash를 사용하기 때문에 다른 스레드를 검색하는 데 운이 없었지만 POSIX 쉘 솔루션을 찾고 있습니다.

답변1

일부 패턴의 경우 유지하려는 변수 부분을 일치시켜 패턴을 "역전"할 수 있습니다.

$ for x in "" a aa abc aabc aaabc aaabca aaabcabc bc bcaa
> do
>     printf %s\\n "${x#"${x%%[!a]*}"}"
> done



bc
bc
bc
bca
bcabc
bc
bcaa

답변2

일반적인 방법으로는 이 작업을 수행할 수 없을 것 같습니다(패턴별 기능을 무시하고 루프 없이 POSIX 셸 구성만 사용합니다.

until [ "${x#a}" = "$x" ]; do x="${x#a}"; done

답변3

a패턴 일치이므로 a일치가 불가능합니다 aaa.

POSIX sh사양은 Korn 쉘의 하위 집합을 기반으로 하고 Korn 쉘에는 (0개 이상의 s 시퀀스와 일치 *(foo)) 및 연산자(1개 이상의 s 시퀀스와 일치, 동일)가 있지만 이는 다음으로 정의되지 않습니다. POSIX는 Bourne 쉘과 역호환되지 않으며 다음과 같은 많은 상황에서 사용할 수 없음을 의미합니다.foo+(foo)foofoo*(foo)

  • find . -name '*(x)'현재는 다음으로 끝나는 파일 이름과 일치해야 합니다.(x)
  • pattern='*(x)'; case $file in ($pattern) ...; esac또는 ${file##$pattern}. 동일한. 이러한 경우 ksh88 또는 pdksh는 이러한 연산자를 인식하지 못한다는 것을 알 수 있습니다.

정규식은 반복을 지원합니다. POSIX는 정규식( expr, grep, sed, ...)과 일치할 수 있는 여러 awk유틸리티를 지정합니다. 일부 쉘에는 이들 중 일부가 내장되어 있습니다. exprAlmquist 쉘에 내장되어 있거나 내장될 수 있습니다. 및 내장을 사용하여 빌드할 수 ksh93있으며 분기 없이 출력을 얻을 수 있습니다. 일부 Ash 기반 쉘은 분기 없이 내장 명령의 단일 호출로 구성된 경우 명령 대체 출력을 얻을 수도 있습니다. 쉘은 분기나 실행 없이 이러한 모든 유틸리티를 호출할 수 있는 쉘의 또 다른 예입니다.exprgrepsedbusybox

반면에, printf당신은 당신의 질문에 사용하고 있습니다아니요ksh88 또는 대부분의 pdksh 파생물에 내장되어 있습니다. 특수 내장 기능 및 export/ getopts/ ... 와 같은 내장 기능(합리적으로만 내장될 수 있음)을 제외하고 readPOSIX는 명령이 내장될 수도 있고 내장되지 않을 수도 있다는 보장을 하지 않습니다.

그래서:

x=$( expr "x$x" : 'xa*\(.*\)' )

a예를 들어, 셸 내부에서 선행 s를 제거할 수 있습니다. 그러나 몇 가지 주의 사항이 있습니다.

  • 결과가 빈 문자열이거나 0으로 표현된 경우 실패 종료 상태가 반환됩니다.
  • 또한 후행 개행 문자도 제거합니다.
  • 연산자를 포함하는 경우 실패를 x방지하기 위해 접두사도 추가해야 한다는 것을 알 수 있습니다 (참조$xexprexprPOSIX 사양의 애플리케이션 사용 섹션상세 사항은).

또는 다음을 사용하여 awk:

x=$(awk 'BEGIN {sub(/^a*/, "", ARGV[1]); print ARGV[1]}' "$x")

또는 sed:

x=$(printf '%s\n' "$x" | sed '1s/^a*//')

( sed라인 단위로 작동하고 stdin 또는 파일을 통한 입력이 필요하므로 여기서는 가장 적합하지 않습니다.)

관련 정보