Bash의 문자열에서 고정 접두사 / 접미사 제거


485

bash스크립트에는 문자열과 접두사 / 접미사가 있습니다. 원래 문자열에서 접두사 / 접미사를 제거해야합니다.

예를 들어 다음과 같은 값이 있다고 가정 해 봅시다.

string="hello-world"
prefix="hell"
suffix="ld"

다음 결과를 얻으려면 어떻게합니까?

result="o-wor"


14
소위 Advanced Bash Scripting Guide에 링크 할 때는 매우주의하십시오. 좋은 조언과 끔찍한 혼합이 포함되어 있습니다.
tripleee

답변:


719
$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor

40
## 및 %%도 있습니다. $ prefix 또는 $ suffix에 와일드 카드가 포함되어 있으면 최대한 제거됩니다.
pts

28
두 줄을 한 줄에 결합하는 방법이 있습니까? 시도 ${${string#prefix}%suffix}했지만 작동하지 않습니다.
static_rtti

28
@static_rtti 아니요, 불행히도 이와 같은 매개 변수 대체를 중첩 할 수 없습니다. 알아, 부끄러운 일이야
Adrian Frühwirth

87
@ AdrianFrühwirth : 전체 언어는 부끄러운 일이지만 너무 유용합니다 :)
static_rtti

8
Google의 Nbash, "bash replacement"는 내가 원하는 것을 발견했습니다.
Tyler

89

sed 사용하기 :

$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor

sed 명령 내에서 ^ 문자는로 시작하는 텍스트와 $prefix후행을 찾습니다.$ 일치 은로 끝나는 텍스트와 일치합니다 $suffix.

Adrian Frühwirth는 아래 의견에서 몇 가지 좋은 점을 지적하지만 sed 이 목적으로 매우 유용 할 수 있습니다. $ prefix와 $ suffix의 내용이 sed에 의해 해석된다는 사실은주의를 기울이는 한 좋거나 나쁠 수 있습니다. 아름다움은 다음과 같이 할 수 있다는 것입니다.

$ prefix='^.*ll'
$ suffix='ld$'
$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor

이것은 당신이 원하는 것일 수 있으며, bash 변수 대체보다 더 강력하고 강력합니다. Spiderman이 말한 것처럼 큰 힘으로 큰 책임을진다는 것을 기억한다면 괜찮을 것입니다.

sed에 대한 빠른 소개는 http://evc-cit.info/cit052/sed_tutorial.html .

쉘 및 문자열 사용에 관한 참고 사항 :

주어진 특정 예의 경우 다음과 같이 작동합니다.

$ echo $string | sed -e s/^$prefix// -e s/$suffix$//

...하지만 다음과 같은 이유로 만 :

  1. echo는 인수 목록에 몇 개의 문자열이 있는지 상관하지 않습니다.
  2. $ prefix 및 $ suffix에는 공백이 없습니다.

공백이 포함되어 있어도 단일 인수로 명령에 표시되므로 명령 행에서 문자열을 인용하는 것이 좋습니다. 동일한 이유로 $ prefix와 $ suffix를 인용합니다. sed에 대한 각 편집 명령은 하나의 문자열로 전달됩니다. 큰 따옴표는 변수 보간을 허용하기 때문에 사용합니다. 우리가 나오지 명령이 문자를받은 것 작은 따옴표를 사용했다 $prefix그리고 $suffix우리가 원하는 것을 확실히이다.

공지 사항, 너무 작은 따옴표 내 사용은 변수를 설정할 때 prefixsuffix. 우리는 확실히 문자열의 어떤 것도 해석하기를 원하지 않으므로 보간이 일어나지 않도록 작은 따옴표로 묶습니다. 다시이 예제에서는 필요하지 않을 수도 있지만 들어가는 것은 좋은 습관입니다.


8
불행히도, 이것은 여러 가지 이유로 나쁜 조언입니다 : 1) 인용되지 않은, $string단어 분리 및 글 로빙의 대상이됩니다. 2) $prefix$suffix식을 포함 할 수있는 sed정규 표현식 또는 전체 명령을 깰 것이다 구분 기호로 사용되는 문자를 예 해석됩니다. 3) sed두 번의 호출 은 필요하지 않으며 ( -e 's///' -e '///'대신 가능) 파이프도 피할 수 있습니다. 예를 들어 string='./ *'and 및 / prefix='./'또는를 고려 하여 1)and 로 인해 심각 하게 중단되는 것을 확인하십시오 2).
Adrian Frühwirth

재미있는 메모 : sed는 거의 모든 것을 구분자로 사용할 수 있습니다. 필자의 경우 경로에서 접두사 디렉토리를 구문 분석했기 때문에을 사용할 수 없으므로 대신을 /사용 sed "s#^$prefix##했습니다. ( #신뢰도 : 파일 이름은을 (를) 포함 할 수 없습니다 . 파일을 제어하므로 안전합니다.)
Olie

@Olie Filenames는 슬래시와 널 문자를 제외한 모든 문자 를 포함 할 수 있으므로 제어하지 않으면 파일 이름에 특정 문자가 포함되지 않는다고 가정 할 수 없습니다.
Adrian Frühwirth

응, 내가 무슨 생각을했는지 모르겠어 아마도 iOS? 던노 파일 이름에는 "#"이 포함될 수 있습니다. 내가 왜 그렇게 말했는지 모르겠다. :)
Olie

@Olie : 원래 의견을 이해 했으므로 #sed의 구분자 로 사용할 선택의 제한으로 인해 해당 문자가 포함 된 파일을 처리 할 수 ​​없다는 의미입니다.
P Daddy

17

접두사와 접미사의 길이를 알고 있습니까? 귀하의 경우 :

result=$(echo $string | cut -c5- | rev | cut -c3- | rev)

또는 더 일반적인 :

result=$(echo $string | cut -c$((${#prefix}+1))- | rev | cut -c$((${#suffix}+1))- | rev)

그러나 Adrian Frühwirth솔루션은 멋지다! 나는 그것에 대해 몰랐다!


14

경로에서 접두사를 제거하기 위해 grep을 사용합니다 (으로 잘 처리되지 않음 sed).

echo "$input" | grep -oP "^$prefix\K.*"

\K 일치하기 전에 모든 문자를 제거합니다.


grep -P비표준 확장입니다. 플랫폼에서 지원되는 경우 더 많은 기능을 사용할 수 있지만 코드를 이식성이 좋으면 모호한 조언입니다.
tripleee

@tripleee 참으로. 그러나 GNU Bash가 설치된 시스템에는 PCRE를 지원하는 grep이 있다고 생각합니다.
블라디미르 페트라 코 비치

1
아니요, 예를 들어 MacOS에는 Bash가 있지만 GNU는 없습니다 grep. 이전 버전은 실제로 -PBSD 의 옵션이 grep있었지만 제거했습니다.
tripleee

9
$ string="hello-world"
$ prefix="hell"
$ suffix="ld"

$ #remove "hell" from "hello-world" if "hell" is found at the beginning.
$ prefix_removed_string=${string/#$prefix}

$ #remove "ld" from "o-world" if "ld" is found at the end.
$ suffix_removed_String=${prefix_removed_string/%$suffix}
$ echo $suffix_removed_String
o-wor

노트:

# $ prefix : #을 추가하면 하위 문자열 "hell"이 처음에 발견 된 경우에만 제거됩니다. % $ suffix : %를 추가하면 하위 문자열 "ld"가 끝에있는 경우에만 제거됩니다.

이것 없이는 "hell"과 "ld"라는 부분 문자열이 중간에서 발견 되더라도 모든 곳에서 제거됩니다.


메모 주셔서 감사합니다! qq : 코드 예제 /에서 문자열 바로 뒤에 슬래시가 있습니다. 무엇입니까?
DiegoSalazar

1
/는 현재 문자열과 하위 문자열을 구분합니다. 하위 문자열은 여기에 게시 된 질문의 접미사입니다.
Vijay Vat

7

=~연산자 사용 :

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ [[ "$string" =~ ^$prefix(.*)$suffix$ ]] && echo "${BASH_REMATCH[1]}"
o-wor

6

작고 보편적 인 솔루션 :

expr "$string" : "$prefix\(.*\)$suffix"

1
Bash를 사용하는 경우 전혀 사용하지 않아야 expr합니다. 그것은이었다 종류의 원래 Bourne 쉘의 일에 편리한 부엌 싱크대 유틸리티 다시,하지만 방법은 날짜 가장 전에지나 지금이다.
tripleee

5

@Adrian Frühwirth 답변 사용 :

function strip {
    local STRING=${1#$"$2"}
    echo ${STRING%$"$2"}
}

이렇게 사용하세요

HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello

0

정규식에서 캡처 그룹을 사용합니다.

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ set +H # Disables history substitution, can be omitted in scripts.
$ perl -pe "s/${prefix}((?:(?!(${suffix})).)*)${suffix}/\1/" <<< $string
o-wor
$ string1=$string$string
$ perl -pe "s/${prefix}((?:(?!(${suffix})).)*)${suffix}/\1/g" <<< $string1
o-woro-wor

((?:(?!(${suffix})).)*)의 내용이 ${suffix}캡처 그룹에서 제외되도록합니다. 예를 들어, 문자열은에 해당합니다 [^A-Z]*. 그렇지 않으면 얻을 것이다 :

$ perl -pe "s/${prefix}(.*)${suffix}/\1/g" <<< $string1
o-worldhello-wor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.