変数でsedコマンドを試してください

変数でsedコマンドを試してください

だから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

sedBashスクリプトでは、次のコマンドを使用します。

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と呼ばれます。yqhttps://kislyuk.github.io/yq/使いやすいjqラッパー(およびjqJSONパーサー)です。

この回答の一部では、質問のコードに示すように両方のold_commitシェル変数を定義したと仮定します。new_commit後で表示される出力は実際に静的文字列として割り当てるのではなく、他の言及されていないプロセス(末尾の$old_commit改行文字を取得するように見える場所)を介して割り当てることを知らせるので、あまり言うことはできません。無視してください。

この実装を使用して以下のキー値を変更するには、image次のものを使用できます。backservicesyq

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

私たちは輸入--argCreateVariableを使用すると、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)。

yqUbuntuなどで入手できるツールは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

関連情報