次の内容のファイルがあります。
<username><![CDATA[name]]></username>
<password><![CDATA[password]]></password>
<dbname><![CDATA[name]]></dbname>
1行目の「名前」を「something」に、2行目の「パスワード」を「somethingelse」に、3行目の「name」を「somethingdifferent」に変更するスクリプトを作成する必要があります。ファイル内で発生するこれらの順序に依存することはできないため、「name」の最初の出現を「something」で、2番目の出現の「name」を「somethingdifferent」で単純に置き換えることはできません。実際に周囲の文字列を検索して、正しいものを見つけて置き換えていることを確認する必要があります。
これまでのところ、私はこのコマンドを試して、最初の「名前」の出現を見つけて置き換えました。
sed -i "s/<username><![CDATA[name]]><\/username>/something/g" file.xml
しかし、それは機能していないので、これらのキャラクターの一部はエスケープする必要があるかもしれないと思います。
理想的には、正規表現を使用して2つの「ユーザー名」の出現を一致させ、「名前」のみを置き換えることができるようにしたいと思います。このようなものですが、sed
:
<username>.+?(name).+?</username>
括弧内の内容を「何か」に置き換えます。
これは可能ですか?
sed -i -E "s/(<username>.+)name(.+<\/username>)/\1something\2/" file.xml
これはあなたが探しているものだと思います。
説明:
\1
、\2
などは、最初の部分でキャプチャされたi番目のグループへの参照です(番号は1から始まります)。-E
は、拡張正規表現を有効にします(+
およびグループ化に必要)。sed -e '/username/s/CDATA\[name\]/CDATA\[something\]/' \
-e '/password/s/CDATA\[password\]/CDATA\[somethingelse\]/' \
-e '/dbname/s/CDATA\[name\]/CDATA\[somethingdifferent\]/' file.txt
/username/
の前のs
は、文字列「username」を含む行でのみ機能するようにsedに指示します。
sed
が難しい要件でない場合は、代わりに専用ツールを使用することをお勧めします。
ファイルが有効なXMLである場合(これらの3つのXMLに見えるタグだけではない)、 XMLStarlet を使用できます。
xml ed -P -O -L \
-u '//username/text()' -v 'something' \
-u '//password/text()' -v 'somethingelse' \
-u '//dbname/text()' -v 'somethingdifferent' file.xml
上記は、正規表現では解決が難しい状況でも機能します。
上記の簡単なデモ:
bash-4.2$ cat file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[name]]></username>
<password>password</password>
<dbname foo="bar"><![CDATA[name]]></dbname>
</apprentice>
</sith>
bash-4.2$ xml ed -O -u '//apprentice/username/text()' -v 'something' -u '//password/text()' -v 'somethingelse' -u '//dbname/text()' -v 'somethingdifferent' file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[something]]></username>
<password>somethingelse</password>
<dbname foo="bar"><![CDATA[somethingdifferent]]></dbname>
</apprentice>
</sith>
$ sed -e '1s/name/something/2' \
-e '3s/name/somethingdifferent/2' \
-e 's/password/somethingelse/2' sample.xml
行番号を示す「s」の前の数字のように、アドレスを使用できます。
また、最後の数字は、最初の一致を置き換えるのではなく、2番目の一致を置き換えるようにsed
に指示します。
s
コマンドの正規表現部分では\[.*^$/
を、置換部分では\&/
を引用符で囲み、改行を追加する必要があります。正規表現は 基本正規表現 であり、さらにs
コマンドの区切り文字を引用符で囲む必要があります。
/
を引用する必要がないように、別の区切り文字を選択できます。代わりにその文字を引用符で囲む必要がありますが、通常、区切り文字を変更するポイントは、置換するテキストまたは置換テキストのいずれにもないものを選択することです。
sed -e 's~<username><!\[CDATA\[name\]\]></username>~<username><![CDATA[something]]></username>~'
グループを使用して、置換テキストの一部を繰り返さないようにし、これらの部分のバリエーションに対応できます。
sed -e 's~\(<username><!\[[A-Z]*\[\)name\(\]\]></username>\)~\1something\2~'
sed -e 's~\(<username>.*[^A-Za-z]\[\)name\([^A-Za-z].*</username>\)~\1something\2~'
「名前」の単語を「何か」の単語に置き換えるには、次を使用します。
sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml
これにより、指定されたWordのすべての出現箇所が置き換えられます。
これまでのところ、すべてが標準出力に出力されています。
sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml > anotherfile.xml
変更を別のファイルに保存します。
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
-r, --regexp-extended
use extended regular expressions in the script.
プロパティファイルの値を置き換える
sed -i -r 's/MAIL\=(.+)/MAIL\[email protected]/' etc/service.properties