だから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
この点を指摘してくれたKusalalanandaに感謝します。
PD 私はUbuntu 0.18.4ディストリビューションを使用しています。
編集する: 2番目のコード部分を使用してください。
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の場合、シェル用に書かれた2つの良いツールがあります。どちらも混乱して.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