2

これが私のtest.env

RABBITMQ_HOST=127.0.0.1
RABBITMQ_PASS=1234

test.sh そして、値をに置き換えるために使用したいtest.env

RABBITMQ_HOST=rabbitmq1
RABBITMQ_PASS=12345

ここに私のtest.shがあります

#!/bin/bash
echo "hello world"

RABBITMQ_HOST=rabbitmq1
RABBITMQ_PASS=12345
Deploy_path="./config/test.env"

sed -i 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='$RABBITMQ_HOST'/'  $Deploy_path
sed -i 's/RABBITMQ_PASS=.*/RABBITMQ_PASS='$RABBITMQ_HOST'/'  $Deploy_path 

しかし、私はエラーがあります

sed: 1: "./config/test.env": invalid command code .
sed: 1: "./config/test.env": invalid command code . 

どうすれば修正できますか?

4

3 に答える 3

3

tl;dr :

macOSにもあるようなBSD Sedでは、コマンドを機能させるために (バックアップ ファイルを作成しないために)の代わりに使用する必要があります。例えば:-i ''-i

sed -i '' 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='"$RABBITMQ_HOST"'/'  "$Deploy_path"

コマンドをGNU と BSD Sedの両方で動作させるには、でないオプション引数(バックアップを作成する) を指定し、それを直接添付します-i

sed -i'.bak' 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='"$RABBITMQ_HOST"'/'  "$Deploy_path" &&
  rm "$Deploy_path.bak" # remove unneeded backup copy

背景情報、(より) ポータブルなソリューション、およびコマンドの改良については、以下を参照してください。


オプションの背景情報

BSD/macOS を使用しているようです。sedその-iオプションには、作成するバックアップ ファイルのサフィックスを指定するオプション引数が必要です。
したがって、(予想に反して)のオプション引数(バックアップ接尾辞) として解釈されるのはスクリプトであり、入力sed ファイル名はscriptとして解釈され、明らかに失敗します。-i

対照的に、コマンドはGNU sed構文を使用します。ここでは、入力ファイルのバックアップ ファイルをインプレースで更新しない-iことを示すために単独で使用できます。

同等のBSD sedオプションは次のとおりです - option-argument を指定するためにの引数を使用する技術的な-i ''必要性に注意してください。これは空の文字列であるためです ( を使用した場合、シェルはそれを見る前に単純に削除します:は事実上、単に)。 ''-i''''sed-i''-i

悲しいことに、これはGNU では機能しません。これは、に直接接続されsedている場合にのみオプション引数を認識し、別の引数を別の引数、つまりscriptとして解釈するためです。-i''

この動作の違いは、オプションの実装の背後にある根本的に異なる設計上の決定に起因しており-i、下位互換性のためにおそらくなくなることはありません。[1]

バックアップ ファイルを作成したくない場合、 BSD と GNUの両方で機能する単一の-i構文はありません。sed

4 つの基本的なオプションがあります。

  • (a) GNUまたはBSDのいずれかのみを使用することがわかっている場合は、それに応じてオプションを構成します: GNU用、BSD 用。sed-i-ised-i ''sed

  • (b)のオプション引数として空でない接尾辞を指定します。これを直接オプションに付けると、両方の実装で機能-iます。例: 。これにより、必ずサフィックス のバックアップ ファイルが作成されますが、後で削除することもできます。-i-i'.bak'.bak

  • (c)sed処理している実装を実行時に決定し、それに応じてオプションを構築し-iます。

  • (d) -i(これは POSIX に準拠していません) を完全に省略し、成功時に元のファイルを置き換える一時ファイルを使用します: sed '...' "$Deploy_path" > tmp.out && mv tmp.out "$Deploy_path".
    これは本質的-iに舞台裏で行われることであり、予期しない副作用を引き起こす可能性があることに注意してください。特に、シンボリックリンクである入力ファイルが通常のファイルに置き換えられます。-i、ただし、元のファイルの特定の属性を保持します。この私の回答の下半分を参照してください。

bash元のコード (2 つの置換による単一の呼び出し) を簡素化し、より堅牢にする (c)の実装を次に示しsedます (変数は二重引用符で囲みます)。

#!/bin/bash

RABBITMQ_HOST='rabbitmq1'
RABBITMQ_PASS='12345'
Deploy_path="test.env"

# Construct the Sed-implementation-specific -i option-argument.
# Caveat: The assumption is that if the `sed` is not GNU Sed, it is BSD Sed,
#         but there are Sed implementations that don't support -i at all,
#         because, as Steven Penny points out, -i is not part of POSIX.
suffixArg=()
sed --version 2>/dev/null | grep -q GNU || suffixArg=( '' )

sed -i "${suffixArg[@]}" '
 s/^\(RABBITMQ_HOST\)=.*/\1='"$RABBITMQ_HOST"'/
 s/^\(RABBITMQ_PASS\)=.*/\1='"$RABBITMQ_PASS"'/
' "$Deploy_path"

$RABBITMQ_HOST上でおよびに対して定義された特定の値を使用して、それらをスクリプトに$RABBITMQ_PASS直接スプライスしても安全ですが、値に、、、または改行のインスタンスが含まれている場合は、コマンドを壊さないように事前にエスケープする必要があります。一般的なプリエスケープを実行する方法については、私のこの回答を 参照してください。sed&/\sed
awkperl


[1] GNU Sed は -i のオプション引数をオプションと見なしますが、BSD Sed は必須と見なします。これは構文仕様にも反映されています。それぞれのmanページ: GNU Sed: -i[SUFFIX]vs. BSD Sed -i extension.

于 2016-11-24T03:53:57.867 に答える
1
ex -sc '%!awk "\
\$1 == \"RABBITMQ_HOST\" && \$2 = \"rabbitmq1\"\
\$1 == \"RABBITMQ_PASS\" && \$2 = 12345\
" FS== OFS==' -cx file
  1. POSIX Sed-iはこのオプションをサポートしていません。ただし、元はファイルをその場で編集できます

  2. データはレコードとフィールドに分かれているため、Awk はこれに適したツールです。

  3. Sed または Awk のいずれの場合でも、改行を利用するか;、1 回の呼び出しですべてを実行できます。

  4. 内部に変数を含まない二重引用符の文字列があり、一重引用符を使用することもできます

  5. エスケープが必要な文字がないときに、ファイル名を引用しました

  6. 引用符で囲まれていない変数の使用がいくつかありますが、良い考えはほとんどありません

于 2016-11-24T02:56:06.787 に答える