web-dev-qa-db-ja.com

を使用して文字列を含む行全体を置き換えます Sed

以下のような特定の行を含むテキストファイルがあります。

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

上記の行全体を置き換える必要があります。

This line is removed by the admin.

検索キーワードはTEXT_TO_BE_REPLACEDです

これにはシェルスクリプトを書く必要があります。 sedを使ってこれを実現するにはどうすればよいですか

257
Rahul

change コマンドを使用して行全体を置き換えることができ、-iフラグを使用してその場で変更を加えることができます。たとえば、GNU sedを使用します。

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo
411
Todd A. Jacobs

行全体を置き換えるには、前後にワイルドカード(.*)を使用する必要があります。

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'
127
Thor

受け入れられた答えは私にはいくつかの理由でうまくいきませんでした:

  • 私のバージョンのsedは、長さゼロの-iを好まない
  • c\コマンドの構文がおかしいのでうまく動かせませんでした
  • 私の問題のいくつかがエスケープされていないスラッシュから来ていることに気づかなかった

だからここに私が考え出した解決策は、ほとんどの場合にうまくいくはずだと思います:

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

そのため、問題を解決するためのサンプル使用法が提示されました。

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile
17
skensell

上記の答え:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

置換文字列/行が変数ではない場合は正常に動作します。

問題はRedhat 5ではcの後の\$をエスケープすることです。二重の\\も動作しませんでした(少なくともRedhat 5では)。

ヒットとトライアルの結果、置換文字列/行が単一行の場合、cの後の\が冗長であることがわかりました。だから私はcの後に\を使わず、変数を単一の置換行として使い、それは喜びでした。

コードは次のようになります。

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

一重引用符の代わりに二重引用符を使用することに注意してください。

10
user4256255

設定ファイルの操作用

私は skensell回答に触発されたこの解決策を思い付きました

configLine [searchPattern] [replaceLine] [filePath]

そうなる:

  • 存在しない場合はファイルを作成します
  • searchPatternが一致した行全体(すべての行)を置き換える
  • パターンが見つからなかった場合は、ファイルの末尾にreplaceLineを追加してください。

関数:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

クレイジーな終了ステータスの魔法は https://stackoverflow.com/a/12145797/1262663から来ています

2
Grain

これまでに提供されたすべての回答は、あなたが置き換えられるテキストについて何か理解していると仮定しています。置き換えられるテキストについて何も知っていないこと、および置き換えたくない同じ内容または類似の内容を含むファイル内に別の行がある可能性があることを前提にした回答を提供しています。さらに、置き換えられる行の行番号を知っていると仮定します。

次の例は、特定の行番号によるテキストの削除または変更を示しています。

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'
2
b_laoshi

私のメークファイルで私はこれを使用します:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PS: いけません -iが実際にファイル内のテキストを変更することを忘れないでください... "Revision"として定義したパターンが変わる場合は、置き換えるパターンも変更します。

出力例

John Doeによって書かれたAbcプロジェクト

改訂:1190

したがって、パターン「Revision:1190」を設定した場合、明らかに「Revision:」のみと定義したのと同じではありません。

1
Martin Pfeffer
bash-4.1$ new_db_Host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_Host/c $new_db_Host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

それはうまくいきます

1
nkl
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

find_replaceファイルには2つの列があります。c1は一致するパターン、c2は置換です。sedループは、変数1のパターンの1つを含む各行を置換します。

1
sjordi

上記と同じです。

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'
0