변수 값에서 여러 개의 후행 공백을 제거하려고 할 때 BASH 4.3.48(SLES12 SP4) 및 BASH 4.4.23(OpenSUSE Leap 15.1)에서 다음과 같은 현상이 나타납니다.
~> xxx="-O -Wall "
~> echo "X${xxx%% }X" # (1)
X-O -Wall X
~> echo "X${xxx%% *}X"
X-OX
~> echo "X${xxx% }X"
X-O -Wall X
~> echo "X${xxx% *}X" # (2)
X-O -Wall X
~> echo "X${xxx%% \*}X"
X-O -Wall X
나는 일을 끝내 거나 (1)
해야 한다고 생각합니다.(2)
설명서에는 다음과 같이 나와 있습니다 ${parameter%%word}
.
일치하는 접미사 패턴을 제거합니다. 경로 이름 확장과 마찬가지로 단어가 확장되어 패턴을 생성합니다. 패턴이 매개변수 확장 값의 후행 부분과 일치하는 경우 확장 결과는 가장 짧은 일치 패턴("%" 케이스) 또는 가장 긴 일치 패턴("%")이 있는 매개변수 확장 값입니다. %'' 사례)이 삭제되었습니다.
문서에 있는 대로(또는 내가 이해한 대로) 작동하지 않기 때문에 이것이 BASH의 버그인 것으로 의심됩니다( -Wall
""의 경우 일치하지 않는 접미사("")가 제거됩니다). %% *
내가 맞나요?
답변1
에서 echo "X${xxx%% }X"
패턴은 단일 공백입니다: . 가장 긴 일치 부분은 공백입니다. 가장 짧은 일치 부분은 공백입니다.
더 많은 경우에는 와일드카드 연산자가 필요합니다 *
. 그러나 이것은 무엇이든 일치합니다 -Wall
. Bash globbing은 직접적으로 동등한 정규식을 지원하지 않습니다 a*
. 당신은해야합니다확장된 와일드카드:
$ shopt -s extglob
$ echo "X${xxx%%+( )}X"
X-O -WallX
답변2
접미사 제거 시 접두사 제거를 사용합니다.
$ xxx="-O -Wall "
$ echo "X${xxx%"${xxx##*[! ]}"}X"
X-O -WallX
- 공백이 아닌 마지막 문자까지 모두 제거하고 후행 공백만 남깁니다.
- 접미사 제거를 위한 패턴으로 이러한 공백을 사용하십시오.
- 내부 매개변수 확장은 패턴으로 해석되는 것을 방지하기 위해 인용되어야 합니다(위의 내용은 필수는 아니지만 다른 경우에 유용할 수 있습니다).
$ bash -c 'xxx="-O -Wall* "; echo "X${xxx%%"${xxx##*[! *]}"}X"'
X-O -WallX
$ bash -c 'xxx="-O -Wall* "; echo "X${xxx%%${xxx##*[! *]}}X"'
XX
이것은 인위적인 예이지만 내부 확장을 인용하지 않으면 포함된 별표는 외부 확장에 의해 쉘 모드로 처리됩니다. 일단 인용하면 말 그대로 별표가 됩니다.
관찰한 동작은 버그가 아니며 단지 쉘 모드가 작동하는 방식에 불과합니다.
${xxx%% }
- 공간은 공간이다
- 단일 공백의 가장 긴 발생은 단일 공백입니다.
${xxx%% *}
- 단일 공백 다음에 아무 것도/아무것도 없는 가장 긴 항목
- 아무것도 포함하지 않음/아무것도 포함하지 않음
-Wall
${xxx% }
- 단일 공백의 발생 횟수가 가장 짧은 것은 단일 공백입니다.
${xxx% *}
- 단일 공백 뒤에 아무것도/없음이 나오는 최소 발생 횟수는 단일 공백입니다.
${xxx%% \*}
\*
백슬래시로 이스케이프 처리된 별표이며 문자 그대로 별표로 해석됩니다.- 변수에서 별표 뒤에는 공백이 없으며 접미사는 삭제되지 않습니다.
답변3
read
또한 작동할 수도 있습니다( IFS
"공간"이 포함되어 있다고 가정).
xxx="-O -Wall "
read -r xxx <<EOF
$xxx
EOF
echo "X${xxx}X"
산출:
X-O -WallX
read
다음을 기준으로 입력을 필드로 분할합니다.IFS
IFS
기본값은 공백/탭/줄 바꿈이므로 선행 및 후행 공백이 모두 제거됩니다.- 변수의 첫 번째 줄에 적용됩니다. (여러줄 변수에는 적합하지 않을 수 있으며
bash
사용 가능합니다read -d ''
.)
답변4
단순 매개변수 확장은 일치시키고 제거할 수 있는 패턴이 매우 제한되어 있습니다. 문자열 끝에서 여러 (중복) 문자를 제거하려면 일반적인 해결책은 먼저 모든 문자를 제거하는 것입니다.아니요문제가 있는 문자 ${xxx##*[! ]}
(모두 후행 공백) 그런 다음 두 번째 단계로 해당 확장에 의해 생성된 모든 것을 끝에서 제거(후행 공백 모두)하면 원하는 결과(후행 공백 제거)가 제공됩니다.
$ xxx="-O -Wall "
$ echo "<${xxx%"${xxx##*[! ]}"}>"
<-O -Wall>
대안으로 bash에서는 확장 와일드카드를 사용할 수 있습니다.
$ shopt -s extglob
$ echo "<${xxx%%+( )}>"
<-O -Wall>
또는 더 높은 수준의 대안으로 정규 표현식을 사용하여 원하는 것과 일치시킬 수 있습니다.
$ regex='(.*[^ ]) +$';
$ [[ $xxx =~ $regex ]] && echo "<${BASH_REMATCH[1]}>" || echo "<$xxx>"
<-O -Wall>
또는 스크립트로:
#!/bin/bash
xxx=${1:-"-O -Wall "}
regex='(.*[^ ]) +$'
if [[ $xxx =~ $regex ]] # if there are trailing spaces
then
echo "<${BASH_REMATCH[1]}>" # Print the string without spaces
else
echo "<$xxx>" # if there are no trailing spaces.
fi