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