web-dev-qa-db-ja.com

Bashコマンドからテキストファイル内を検索して置換する

与えられた入力文字列を検索して置換する最も簡単な方法は何ですか?abc、別の文字列を置換する(ファイル/tmp/file.txt内のXYZ

私はSSHを介してコマンドを実行するためにアプリを書いてIronPythonを使用しています - しかし私はUnixをよく知らないので何を探すべきかわかりません。

Bashは、コマンドラインインターフェイスであることとは別に、非常に強力なスクリプト言語になることができると聞いたことがあります。だから、これが本当なら、私はあなたがこれらのような行動を実行できると思います。

Bashでそれを行うことができますか、そして私の目標を達成するための最も簡単な(1行の)スクリプトは何ですか?

469
Ash

最も簡単な方法はsed(またはPerl)を使うことです。

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

-iオプションにより、sedを呼び出してインプレース編集を行います。これはbashから呼び出すことができます。

本当にbashだけを使いたいのであれば、次のようにします。

while read a ; do echo ${a//abc/XYZ} ; done < /tmp/file.txt > /tmp/file.txt.t ; mv /tmp/file.txt{.t,}

これは各行をループして置換をし、一時ファイルに書き込みます(入力を壊したくない)。最後の移動は一時的に元の名前に移動します。

791
johnny

ファイル操作は通常Bashによって行われるのではなく、Bashによって呼び出されたプログラムによって行われます。

> Perl -pi -e 's/abc/XYZ/g' /tmp/file.txt

-iフラグはインプレース置換をするようにそれに伝えます。

元のファイルのバックアップを取る方法など、詳細についてはman perlrunを参照してください。

155
Alnitak

私はこれにつまずいたので驚きました...

"replace" パッケージに同梱されている "mysql-server" というコマンドがありますので、インストールしていれば試してみてください。

# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt

# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"

詳しくは man replace を参照してください。

64
rayro

これは古い投稿ですが、@ centurianが一重引用符は何も展開されないことを意味しているので、変数を使用したい人のためのものです。

変数を取得する簡単な方法は、文字列の連結を行うことです。これはbashの並置によって行われるため、次のように動作するはずです。

sed -i -e 's/'"$var1"'/'"$var2"'/g' /tmp/file.txt

39
zcourts

Bashは他のシェルと同様に、他のコマンドを調整するための単なるツールです。通常は標準のUNIXコマンドを使おうとしますが、もちろんBashを使って自分のコンパイル済みプログラム、他のシェルスクリプト、Python、Perlスクリプトなどを呼び出すこともできます。

この場合、それを実行する方法がいくつかあります。

ファイルを読み、それを別のファイルに書き込み、あなたが行っているように検索/置換をしたいのなら、sedを使います。

sed 's/abc/XYZ/g' <infile >outfile

ファイルをその場で編集したい場合(ファイルをエディタで開いて編集してから保存する場合)、行エディタ 'ex'に指示を与えます。

echo "%s/abc/XYZ/g
w
q
" | ex file

Exはフルスクリーンモードのないviのようなものです。あなたはviの ':'プロンプトと同じコマンドを与えることができます。

37
slim

このスレッドを他の人の間で見つけました、そしてそれが最も完全な答えを含んでいることに同意するので私も追加します:

1)sedとedはとても便利です...手で! @Johnnyからのこのコードを見てください。

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

2)私の制限がシェルスクリプトでそれを使用することである場合、abcやXYZの代わりに変数を内部で使用することはできません。 これ 少なくとも私が理解していることと一致するようです。だから、私は使用することはできません:

x='abc'
y='XYZ'
sed -i -e 's/$x/$y/g' /tmp/file.txt
#or,
sed -i -e "s/$x/$y/g" /tmp/file.txt

しかし、私たちは何ができますか? @Johnnyは「while read ...」を使用すると述べたが、残念ながらこれで話は終わりではない。以下は私とうまくいった:

#edit user's virtual domain
result=
#if nullglob is set then, unset it temporarily
is_nullglob=$( shopt -s | egrep -i '*nullglob' )
if [[ is_nullglob ]]; then
   shopt -u nullglob
fi
while IFS= read -r line; do
   line="${line//'<servername>'/$server}"
   line="${line//'<serveralias>'/$alias}"
   line="${line//'<user>'/$user}"
   line="${line//'<group>'/$group}"
   result="$result""$line"'\n'
done < $tmp
echo -e $result > $tmp
#if nullglob was set then, re-enable it
if [[ is_nullglob ]]; then
   shopt -s nullglob
fi
#move user's virtual domain to Apache 2 domain directory
......

3)nullglobが設定されているかどうかがわかるように、*を含む文字列があると奇妙に振る舞います。

<VirtualHost *:80>
 ServerName www.example.com

になる

<VirtualHost ServerName www.example.com

最後の山括弧はなく、Apache2もロードできません。

4)この種の構文解析は、1ヒット検索と置換より遅くなるはずですが、すでに見たように、1つの解析サイクルのうち4つの異なる検索パターンに対して4つの変数があります。

私は問題の与えられた仮定で考えることができる最も適切な解決策。

32
centurian

Sedが使えます

sed -i 's/abc/XYZ/gi' /tmp/file.txt

大文字と小文字を区別しない -iを使用してください。検索するテキストがabcまたはABCまたはAbCなどであることがわからない場合.

ファイル名がわからなくてもfindsedを使えます。

 find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;

すべてのpythonファイルで見つけて置き換えます。

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
18
MMParvin

Edコマンドを使ってファイル内検索や置換をすることもできます。

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 

bash-hackersサイトでもっと見る

11
chrio

URLを "/"文字に置き換える場合は注意してください。

それを行う方法の例:

sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"

抽出元: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html

8
Linux4you

作業中のファイルがそれほど大きくなく、一時的に変数に格納しても問題ない場合は、ファイル全体に一度にBash文字列置換を使用できます。1行ずつ移動する必要はありません。

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt

ファイル全体の内容は、改行を含めて1つの長い文字列として扱われます。

XYZは$replacementなどの変数にすることができます。ここでsedを使用しないことの利点の1つは、検索または置換文字列にsedパターンの区切り文字が含まれる可能性があるということです。欠点は、正規表現やsedのより洗練された操作を使用できないことです。

7
johnraff

次のシェルコマンドを試してください。

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
4
J Ajay

ファイル内のテキストを非対話的に編集するには、vimなどのインプレーステキストエディタが必要です。

これは、コマンドラインから使用する簡単な例です。

vim -esnc '%s/foo/bar/g|:wq' file.txt

これは @slim answer of ex editorと同じで、基本的に同じものです。

ここにいくつかのex実用的な例があります。

ファイル内のテキストfoobarに置き換えます。

ex -s +%s/foo/bar/ge -cwq file.txt

複数のファイルから末尾の空白を削除する:

ex +'bufdo!%s/\s\+$//e' -cxa *.txt

トラブルシューティング(端末が動かなくなった場合):

  • 詳細メッセージを表示するには、-V1パラメータを追加します。
  • -cwq!で強制終了してください。

また見なさい:

4
kenorb

あなたはbashスクリプト内でもpythonを使うことができます。私はここでいくつかの主な答えであまり成功していませんでした、そしてこれがループを必要とせずに動作することがわかりました:

#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'

s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()
2
micalith

あなたはrplコマンドを使用することができます。たとえば、phpプロジェクト全体でドメイン名を変更したいとします。

rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/  

これは明確な原因の対立ではありませんが、非常に迅速で便利です。 :)

1
zalex