쉘 스크립트에서 하나의 하위 문자열을 다른 문자열로 교체


821

나는 "Suzi와 Marry를 좋아한다"고 "Suzi"를 "Sara"로 바꾸고 싶다.

#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...

결과는 다음과 같아야합니다.

firstString="I love Sara and Marry"

16
Suzi를 부드럽게 내려 놓는 것으로 시작하겠습니다. :)
코드 스니퍼

당신이 아니에요! 그것은 Suzi와 대화 할 줄이
었어 야했는데

답변:


1358

처음 나타나는 패턴을 주어진 문자열로 바꾸려면 다음을 사용하십시오 .${parameter/pattern/string}

#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/$secondString}"    
# prints 'I love Sara and Marry'

모든 발생 을 바꾸려면 다음을 사용하십시오 .${parameter//pattern/string}

message='The secret code is 12345'
echo "${message//[0-9]/X}"           
# prints 'The secret code is XXXXX'

(이 설명되어 배쉬 참조 설명서 §3.5.3, "쉘 매개 변수 확장을" .)

이 기능은 POSIX (Bash 확장)에 의해 지정되지 않았으므로 모든 Unix 쉘이이를 구현하지는 않습니다. 관련 POSIX 문서 는 Open Group 기술 표준 기본 사양, Issue 7 , Shell & Utilities 볼륨, §2.6.2 "매개 변수 확장"을 참조하십시오 .


3
@ruakh 또는이 조건 으로이 진술을 작성하는 방법. Suzi 또는 Marry를 새 문자열로 바꾸려는 경우에만.
Priyatham51

3
@ Priyatham51 : 내장 기능이 없습니다. 하나만 교체하고 다른 하나만 교체하십시오.
ruakh

4
@Bu : 아니요. \n그 맥락에서 개행 문자가 아니라 자체를 나타 내기 때문 입니다. 나는 현재 테스트하기에 Bash를 가지고 있지 않지만, 당신은 다음과 같은 것을 쓸 수 있어야한다 $STRING="${STRING/$'\n'/<br />}". (아마도 STRING//-대신에 STRING/
-replace

25
분명히, 이것은 조금 혼란 스러우므로 첫 번째 부분은 변수 참조 여야합니다. 당신은 할 수 없습니다 echo ${my string foo/foo/bar}. 당신은 필요합니다input="my string foo"; echo ${input/foo/bar}
Henrik N

2
@mgutt :이 답변은 관련 문서로 연결됩니다. 문서가 완벽하지는 않습니다. 예를 들어 //직접 언급하는 대신 " 패턴 이 ' /'로 시작 하는 경우 '가 어떻게 발생하는지 언급합니다 (이 문장의 나머지 /부분은 실제로는 패턴)-하지만 더 나은 소스를 모릅니다.
ruakh

208

이것은 bash 문자열 조작으로 완전히 수행 할 수 있습니다.

first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second}

첫 번째 항목 만 대체합니다. 그것들을 모두 바꾸려면 첫 번째 슬래시를 두 배로하십시오.

first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now "Sara, Sara, Sara"

9
전역 대체 옵션으로 승인 된 답변을 편집하는 대신 승인 된 답변을 복제하는 답이 있습니까? 그리고 정규 표현식이 추가되는 동안 지원됩니다. 그리고 "나쁜 대체"에 대해 설명합니다. 당신은 충분히 포인트, @Kevin :이
댄 Dascalescu

6
O : 그들이 모두 동일한 분에 응답 한 표시
제이미 Hutber

76

대시의 경우 모든 이전 게시물이 작동하지 않습니다

POSIX sh호환 솔루션은 다음과 같습니다.

result=$(echo "$firstString" | sed "s/Suzi/$secondString/")

1
나는 이것을 얻었다 : $ echo $ (echo $ firstString | sed 's / Suzi / $ secondString / g') $
secondString을

2
@Qstnr_La는 변수 대체를 위해 큰 따옴표를 사용합니다 :result=$(echo $firstString | sed "s/Suzi/$secondString/g")
emc

1
변수에 출력하는 방법을 보여주는 플러스 1 감사!
요리사 파라오

2
작은 따옴표를 수정하고 echo인수 주위에 누락 된 따옴표를 추가했습니다 . 간단한 문자열로 인용하지 않고 기만적으로 작동하지만 사소하지 않은 입력 문자열 (불규칙한 간격, 쉘 메타 문자 등)을 쉽게 끊습니다.
tripleee

sh (AWS Codebuild / Ubuntu sh)에서 마지막에 이중이 아닌 단일 슬래시가 필요하다는 것을 알았습니다. 위의 주석에도 단일 슬래시가 표시되므로 주석을 편집하겠습니다.
Tim

67

이 시도:

 sed "s/Suzi/$secondString/g" <<<"$firstString"

19
실제로 Sed가 필요하지 않습니다. Bash는 이러한 종류의 대체를 기본적으로 지원합니다.
ruakh

12
나는 이것이 "bash"로 태그되어 있지만 다른 쉘을 위해 간단한 것이 필요했기 때문에 여기에 왔다고 생각한다. 이것은 wiki.ubuntu.com/…에 대한 간결한 대안 입니다.
natevw

3
이것은 재 / 대시 또는 다른 POSIX sh에 효과적입니다.
Yoshua Wuyts

2
나는 오류 sed를
Nam G VU

1
stdin과 함께 작동하는 첫 번째 대답은 파이프 라이닝 문자열에 좋습니다.
Dinei

46

sed문자열에 RegExp 문자 가있는 경우 보다 bash를 사용하는 것이 좋습니다 .

echo ${first_string/Suzi/$second_string}

그것은 Windows에 이식 가능하며 Bash 3.1만큼 오래되었습니다.

이스케이프에 대해 크게 걱정할 필요가 없음을 보여주기 위해

/home/name/foo/bar

이것으로 :

~/foo/bar

그러나 /home/name처음에있는 경우에만 . 우리는 필요하지 않습니다 sed!

bash는 마법 변수를 제공 $PWD하고 다음 $HOME과 같이 할 수 있습니다.

echo "${PWD/#$HOME/\~}"

편집 : 인용 / 이스케이프에 대한 주석에서 Mark Haferkamp 에게 감사드립니다 ~. *

변수 $HOME에 슬래시가 어떻게 포함되어 있는지 확인 하지만 아무것도 깨지 않았습니다.

추가 자료 : Advanced Bash-Scripting Guide .
사용 sed이 필수 인 경우 모든 문자 하십시오 .


이 대답은 사용자 정의를 실행할 때마다 새 변수를 정의하지 않도록 명령 sed과 함께 사용하지 못하게했습니다 . Bash는 마술 변수보다 문자열 대체를 위해 명령의 출력을 사용하는보다 일반적인 방법을 제공합니까? 귀하의 코드 는 Bash가 $ HOME으로 확장하지 못하게하기 위해 를 피해야 했습니다. 또한 명령에서의 기능은 무엇입니까? pwd$PS1~#
Mark Haferkamp 0

1
@MarkHaferkamp "추가 읽기 권장"링크 에서이 내용을 참조하십시오 . "탈출"에 관하여 ~: 내가 물건을 어떻게 인용했는지 주목하십시오. 항상 물건을 인용하십시오! 그리고 이것은 마법 변수에 대해서만 작동하지 않습니다. 모든 변수는 bash 내에서 문자열 길이 등을 대체하고 대체 할 수 있습니다. $PS1빠른 노력을 축하합니다 . $PROMPT_COMMAND다른 프로그래밍 언어에 더 익숙하고 컴파일 된 프롬프트를 코딩하려는 경우 에도 관심이 있을 수 있습니다.
Camilo Martin

"추가 정보"링크는 "#"를 설명합니다. Bash 4.3.30에서 echo "${PWD/#$HOME/~}"my를 $HOME으로 바꾸지 마십시오 ~. 교체 ~와 함께 \~또는 '~'작동합니다. 이 중 하나는 다른 배포판의 Bash 4.2.53에서 작동합니다. ~호환성을 높이기 위해 게시물을 업데이트하거나 인용하지 않으시겠습니까? "매직 변수"질문의 의미는 다음과 같습니다. 예를 들어, uname변수로 변수를 먼저 저장하지 않고 Bash의 변수 대체를 사용할 수 있습니까 ? 내 개인에 관해서는 $PROMPT_COMMAND, 그것은 복잡 .
Mark Haferkamp

@ MarkHaferkamp Whoa, 당신은 완전히 옳아 요. 지금 답변을 업데이트하겠습니다.
Camilo Martin

1
@MarkHaferkamp Bash와 그 모호한 함정 ... : P
카밀로 마틴

19

내일 당신이 결혼을 좋아하지 않기로 결정하면 그녀도 교체 될 수 있습니다.

today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt

연인을 떠나는 방법은 50 가지가 있어야합니다.


9

댓글을 추가 할 수 없으므로 @ruaka 예제를 더 읽기 쉽게 작성하려면 다음과 같이 작성하십시오

full_string="I love Suzy and Mary"
search_string="Suzy"
replace_string="Sara"
my_string=${full_string/$search_string/$replace_string}
or
my_string=${full_string/Suzy/Sarah}

내가 당신의 모범에 올 때까지 나는 다른 방향으로 순서를 이해했습니다. 이것은 무슨 일이 일어나고 있는지 명확히하는 데 도움이되었습니다
raghav710

5

Roman Kazanovskyi답변 과 달리 순수 POSIX 셸 방법은 외부 도구가 필요하지 않으며 셸 자체 고유 매개 변수 확장 입니다. 긴 파일 이름이 최소화되므로 코드가 한 줄에 더 적합합니다.sed

f="I love Suzi and Marry"
s=Sara
t=Suzi
[ "${f%$t*}" != "$f" ] && f="${f%$t*}$s${f#*$t}"
echo "$f"

산출:

I love Sara and Marry

작동 방식 :

  • 가장 작은 접미사 패턴을 제거하십시오. "${f%$t*}"반환 " I love"접미사가있는 경우 $t" Suzi*"에 $f" ". I love Suzi and Marry

  • 그러나 경우 t=Zelda, 다음 "${f%$t*}"아무 것도 삭제하지 않고, 전체 문자열을 "반환 I love Suzi and Marry".

  • 경우에 테스트하는 데 사용됩니다 $t$f[ "${f%$t*}" != "$f" ]로 평가되는 사실 경우 $f문자열이 "포함 Suzi*"과 거짓 이 아니라면.

  • 테스트가 true를 반환하면 가장 작은 접미사 패턴 제거${f%$t*} " I love"와 가장 작은 접두사 패턴 제거 ${f#*$t} " and Marry"를 사용하여 두 번째 문자열 $s" Sara"을 사이에 두고 원하는 문자열을 구성 하십시오 .


5

나는 이것이 오래되었다는 것을 알고 있지만 아무도 awk 사용에 대해 언급하지 않았기 때문에 :

    firstString="I love Suzi and Marry"
    echo $firstString | awk '{gsub("Suzi","Sara"); print}'

1
그 트릭은 분할하려는 것이 실제로 변수가 아니라 텍스트 파일에있는 경우 갈 수있는 방법입니다. 감사합니다, @Payam!
Felipe SS Schneider

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.