![변수와 함께 sed 명령을 사용해보십시오](https://linux55.com/image/190318/%EB%B3%80%EC%88%98%EC%99%80%20%ED%95%A8%EA%BB%98%20sed%20%EB%AA%85%EB%A0%B9%EC%9D%84%20%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%8B%AD%EC%8B%9C%EC%98%A4.png)
그래서 bash 스크립트에 다음 변수를 정의했습니다.
new_commit="back:h3912kk"
old_commit="back:1.0.1"
file = docker-compose.yml
그런 다음 다음 yml이 있습니다 $file
.
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.4
volumes:
- /home/mongo_files:/data/db
networks:
my_network:
back:
container_name: back
image: index.docker.io/gg/back:1.0.1
networks:
my_network
networks:
my_network:
라인을 바꾸고 싶어요
image: index.docker.io/gg/back:1.0.1
~을 위한
image: index.docker.io/gg/back:h3912kk
sed
Bash 스크립트에서 다음 명령을 사용합니다.
echo sed -i "s/$old_commit/$new_commit/" $file
하지만 다음과 같은 오류가 발생합니다.
sed: -e expression #1, char 12: unterminated `s' command
물론 docker-compose 파일은 업데이트되지 않습니다.
내가 뭘 잘못했나요?
echo 명령을 실행하면 다음과 같이 표시됩니다.
sed -i s/back:1.0.1
/back:h3912kk/ docker-compose.yml
echo가 같은 줄에 명령을 표시하지 않는 이유는 무엇입니까?
편집하다:
@Kusalananda가 말했듯이 old_commit 변수는 정적 파일이 아닙니다. 이것이 귀하가 제공한 관련 답변을 재현할 수 없는 주된 이유인 것 같습니다 $old_commit
(그래도 문제가 있다고 가정하지는 않습니다).
매개 변수를 가져오기 위해 old_commit
다음 명령을 사용하여 관심 있는 기준을 충족하는 yml 파일의 줄을 찾습니다. 전체 코드는 다음과 같습니다.
output='back:h3912kk'
# here I split the name of the repo and the commit by ':'
readarray -d ':' -t array_new_commit <<< "$output"
repo="${array_new_commit[0]}"
file=docker-compose.yml
# here I loop over the lines of the yml file:
while read -r line; do
# if a line contains the repo name str and image str I generate a line with the new commit
if [[ $line == *$repo* && $line == *"image"* ]]; then
# old_line=$line
readarray -d '/' -t array_old_commit <<< "$line"
old_commit=${array_old_commit[-1]}
# new_line="${array_old_commit[0]}:${array_old_commit[1]}:$new_commit"
fi
done<"$file"
어쨌든 (왜인지는 모르겠지만 bash를 처음 사용하는 경우) 이 변수를 이런 방식으로 생성해도 실제로는 정적 변수처럼 사용할 수 없습니다. (나는 이것을 정말로 이해하고 싶다)
변수를 yml 파일의 변수 old_commit
로 바꾸는 해결 방법을 알려주실 수 있나요 ?new_commit
이 점을 지적해주신 Kusalananda님께 다시 한 번 감사드립니다.
PD 저는 우분투 0.18.4 배포판을 사용하고 있습니다.
편집하다: 두 번째 코드 부분을 사용하십시오.
yq -Y --arg new "$new_commit" --arg reposit "$repo" \
'".services." + $reposit + ".image |=index.docker.io/gg/" + $new' docker-compose.yml
내 결과는 다음과 같습니다
.services.back.image |=index.docker.io/gg/back:h3912kk
...
답변1
YAML 파일이나 구조화된 문서 형식(YAML, JSON, XML 등)으로 작성된 파일을 사용해서는 안 되며 sed
, 해당 문서 형식용으로 작성된 파서를 사용해야 합니다.
YAML의 경우 셸용으로 작성된 두 가지 좋은 도구가 있습니다. 둘 다 혼란스럽게 .fromyq
이라고 합니다.yq
https://kislyuk.github.io/yq/사용하기 쉬운 jq
래퍼(및 jq
JSON 파서)입니다.
이 답변의 일부에서는 질문의 코드에 표시된 대로 old_commit
두 쉘 변수를 모두 정의했다고 가정합니다 . new_commit
나중에 표시되는 출력은 실제로 정적 문자열로 할당하는 것이 아니라 언급하지 않은 다른 프로세스( $old_commit
후행 개행 문자를 얻는 것처럼 보이는 곳)를 통해 할당한다는 것을 알려주므로 많이 말할 수는 없습니다. 무시해.
이 구현을 사용하여 아래의 키 값을 변경하려면 image
다음을 사용할 수 있습니다.back
services
yq
yq -Y '.services.back.image |= "index.docker.io/gg/back:h3912kk"' file.yml
또는 원하는 $new_commit
값을 사용하세요.
new_commit='back:h3912kk'
yq -Y --arg new "$new_commit" \
'.services.back.image |=
"index.docker.io/gg/" + $new' file.yml
우리는수입--arg
CreateVariable을 사용하면 yq
쉘 변수 값을 $new
표현식 문자열에 직접 삽입하는 대신 표현식에 추가할 수 있습니다. 이렇게 하면 값이 올바르게 인코딩 yq
되고 코드에 코드 삽입 취약점이 없는지 확인할 수 있습니다.
또는 문자열을 언급하지 않고 다음을 수행합니다 index.docker.io/gg/
.
new_commit='back:h3912kk'
yq -Y --arg new "$new_commit" \
'.services.back.image |=
sub("[^/]*$"; "") + $new' file.yml
또는 저장소에 대해 별도의 변수를 사용하십시오.
new_commit='back:h3912kk'
yq -Y --arg new "$new_commit" --arg repo 'back' \
'.services[$repo].image |=
sub("[^/]*$"; "") + $new' file.yml
$old_commit
정적 경로를 사용하는 대신 문자열을 사용하여 교체할 올바른 이미지를 찾을 수도 있습니다 .
old_commit='back:1.0.1'
new_commit='back:h3912kk'
yq -Y --arg old "$old_commit" --arg new "$new_commit" \
'(.services[].image | select(endswith($old))) |=
(rtrimstr($old) + $new)' file.yml
여기서 우리는 선택합니다모두 .services.*.image
의 임의의 문자열로 끝나는 경로의 $old_commit
끝 부분을 잘라서 로 바꿉니다 $new_commit
.
질문의 샘플 YAML 문서를 고려하면 위의 각 명령은 다음을 생성합니다.
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.4
volumes:
- /home/mongo_files:/data/db
networks:
my_network: null
back:
container_name: back
image: index.docker.io/gg/back:h3912kk
networks: my_network
networks:
my_network: null
출력을 새 파일로 쉽게 리디렉션할 수 있습니다(또는 YAML 문서의 내부 편집 사용 --in-place
).
yq
Ubuntu 등에서 얻는 도구는 snap
다릅니다. 저는 이것을 사용하여 YAML을 JSON으로 변환하고 다시 JSON으로 변환하는 경향이 있습니다.
yq -j e file.yml |
jq '.services.back.image |= "index.docker.io/gg/back:h3912kk"' |
yq -P e
예제 YAML 파일이 주어지면 위와 동일한 출력이 생성됩니다. 위의 표현은 jq
동일한 의미를 지닌 이 답변의 상단에 있는 어떤 표현으로든 대체될 수 있습니다.
답변2
yaml 파일에 sed를 사용한다고 판단하지 않겠습니다. 모든 사람은 자신이 원하는 방식으로 일을 완수합니다.
나는 얼마 전에 같은 문제에 직면했고 sed 정규식에서 변수를 "중괄호"하면 모든 것이 작동하기 시작하는 것 같습니다.
$ cat $file
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.4
volumes:
- /home/mongo_files:/data/db
networks:
my_network:
back:
container_name: back
image: index.docker.io/gg/back:1.0.1
networks:
my_network
networks:
my_network:
그 다음에:
$ sed s/${old_commit}/${new_commit}/ $file
다음 결과를 제공합니다.
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.4
volumes:
- /home/mongo_files:/data/db
networks:
my_network:
back:
container_name: back
image: index.docker.io/gg/back:h3912kk
networks:
my_network
networks:
my_network:
도움이 되었기를 바랍니다..
MacOS 10.13(bash 5.1.4.1, gnu sed 4.8) 및 Ubuntu 16.04(bash 4.3.48, gnu sed 4.2.2)에서 테스트되었습니다.
답변3
yq -i -Y --arg new "$VERSION" '.tool.image.tag |= $new' values.yaml