파일의 매개변수를 일치시키고 등호 문자 뒤의 값만 바꿉니다.

파일의 매개변수를 일치시키고 등호 문자 뒤의 값만 바꿉니다.

다음 예제 파일에서

more ambari-agent.ini
[server]
hostname=AABB

파일의 단어를 일치시키고 hostname그 뒤의 값 (동일 문자)만 바꾸려고 합니다.=

그래서 우리는 해냈습니다

VAR=server_100

sed -ire "s/(hostname=)[^=]*$/\$VAR/"  /tmp/ambari-agent.ini

하지만 우리는 아직

more ambari-agent.ini
[server]
hostname=AABB

예상되는 결과는 다음과 같아야 하지만

more ambari-agent.ini
[server]
hostname=server_100

우리가 어디에서 잘못됐나요?

답변1

VAR=anything
escaped_VAR=$(
  printf '%s\n' "$VAR" |
    LC_ALL=C sed 's|[/&\\]|\\&|g;$!s/$/\\/'
)

LC_ALL=C sed -E -i -e "s/^(hostname=).*/\1$escaped_VAR/" -- "$the_file"

FreeBSD/macOS의 경우 로 sed바꾸십시오 .-i-i ''

GNU(결국 FreeBSD 대신 GNU를 복사한 NetBSD/OpenBSD) 및 FreeBSD의 경우 sed백업 -i확장 이름이라는 하나의 인수를 사용합니다. GNU의 경우 sed이 매개변수는 선택사항이며 지속되어야 -i하지만 FreeBSD의 경우 sed필수입니다(그러나 빈 매개변수를 전달하면 백업 복사본 보관도 비활성화됩니다).

-ire-iGNU와 FreeBSD 모두에서 이는 with as 매개변수 로 해석됩니다 . FreeBSD에서는 인수를 취하는 것으로 해석되고, GNU에서는 인수를 취하지 않고 옵션이 따라오는 것으로 해석됩니다.re-i -e-i-e-i-esed

기타 참고사항:

  • -rERE 용 GNU , -E. 이는 POSIX에 의해 지정됩니다. 어쨌든 여기서는 ERE가 필요하지 않습니다. BRE에 비해 ERE의 유일한 특징은 (교대)이며 나머지는 구문 차이입니다. 잘 작동합니다.-Esed|sed -i "s/^\(hostname=\).*/\1$escaped_VAR/"
  • .*C입력에 (따라서 LC_ALL=C) 이외의 로케일에서 유효한 문자를 형성하지 않는 바이트 시퀀스가 ​​포함된 경우 줄 끝까지 일치하지 않을 수 있습니다.
  • 전달된 코드의 확장 asis는 콘텐츠가 삭제되지 않고 , 및 개행 문자가 이스케이프되는 경우 명령 주입 $VAR취약점을 구성합니다. 위와 같이 사용하면 쉘 변수의 내용이 아닌 리터럴만 대체됩니다.sed&\/\$VAR$VAR$VAR
  • 값(또는 주석일 수도 있는 오른쪽에 있는 항목)이 포함되지 않은 경우, 그렇게 하면 s/(hostname=)[^=]*$/$escaped_VAR/해당 줄이 대체됩니다. 나는 이것이 의도적인 것이라는 것을 깨닫지 못했습니다.hostnamehostname==
  • 그렇지 않은 경우 파일의 어느 위치에서나 ^일치합니다 . 줄 시작 부분에 있는 인스턴스 만 완료되었는지 확인하세요 . 선행 공백을 허용하려면 항상 다음을 사용할 수 있습니다.hostname=^hostname="/^([[:space:]]*hostname...

1 POSIX ERE에는 BRE의 역참조 기능도 부족하지만 현재 대부분의 ERE 구현에서는 이를 확장으로 지원합니다.

답변2

이전 답변도 기능으로 작동하므로 거기에 대한 의견에 답변하기에는 평판이 부족합니다.

VAR=anything
function escape() { printf '%s\n' "$1" | LC_ALL=C sed 's|[+/&\\]|\\&|g;$!s/$/\\/' }
LC_ALL=C sed -E -e "s/^(hostname=).*/\1$(escape $VAR)/" -i -- "$file"

+규칙을 이스케이프하도록 문자를 수정했습니다 .

VAR이는 동적으로 또는 다른 방식으로 제공되는 대체 값에도 적용됩니다 .

LC_ALL=C sed -E -e "s/^(> API_SECRET=).*/\1$(escape $(pwgen -n 64 1))/" -i -- diff.patch
VAR="admin"; LC_ALL=C sed -E -e "s/^(+SP_ADMIN_USER=).*/\1$(escape "${VAR}")/" -i diff.patch

-e이 명령은 잠재적 으로 중복될 수 있다는 점에서 원래 예와 다르며 생략되었습니다 --.

이 논리는 완전히 생략된 다른 함수를 사용하여 추가로 매개변수화할 수 있습니다 VAR.

function replace() { LC_ALL=C sed -E -e "s/^($(escape "${1}")).*/\1$(escape "${2}")/" -i "${3}" }
replace "+ADMIN_USER=" "admin" diff.patch

그런 다음 프로그래밍 방식으로 사용하여 선택한 행의 시작 부분 이후의 값을 바꿀 수 있습니다.

관련 정보