web-dev-qa-db-ja.com

Linuxのコマンドラインで複数のファイルの文字列を置き換える方法

私は、サーバへのアクセスがsshだけで、フォルダ内のたくさんのファイルの文字列を置き換える必要があります。これどうやってするの?

341
mridul4c
cd /path/to/your/folder
sed -i 's/foo/bar/g' *

"foo"の出現は "bar"に置き換えられます。

469
kev

Kasparの答えに似ていますが、行のすべての出現箇所を置き換えるためのgフラグが付いています。

find ./ -type f -exec sed -i 's/string1/string2/g' {} \;

グローバルな大文字と小文字を区別しない場合:

find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
194

@ kevの答えは良いですが、直下のディレクトリにあるファイルにのみ影響します。以下の例では、grepを使ってファイルを再帰的に見つけます。それは私のためにいつも働きます。

grep -rli 'old-Word' * | xargs -i@ sed -i 's/old-Word/new-Word/g' @
118
pymarco

これは私のために働いた:

find ./ -type f -exec sed -i 's/string1/string2/' {} \;

しかし、これはしませんでした:sed -i 's/string1/string2/g' *。たぶん、「foo」はstring1であり、「bar」はstring2ではありませんでした。

30
Kaspar L. Palgi

これに対する既にいくつかの標準的な答えがあります。通常、 find を使用してファイルを再帰的にリストしてから、 sed または Perl を使用して操作を実行できます。

ほとんどの場合、 rpl の方が覚えやすいでしょう。これは置き換え(foo - > bar)で、すべてのファイルに対して再帰的に行われます。

rpl -R foo bar .

おそらくそれをインストールする必要があるでしょう(apt-get install rplまたはそれに類似したもの)。

しかし、正規表現や後退代入、あるいはファイル名の変更や検索と置換を含むもっと難しい仕事のために、私が知っている最も一般的で強力なツールは Representn 小さなPythonスクリプト私はしばらくの間、いくつかのとんでもない名前の変更とリファクタリングのタスクについて書きました。あなたがそれを好むかもしれない理由は:

  • ファイルの名前の変更、およびファイルの内容の検索と置換をサポートします。
  • 検索と置換を実行する前に変更を確認してください。
  • 後方置換、単語全体、大文字と小文字を区別しない、および大文字と小文字を区別する(foo - > bar、Foo - > Bar、FOO - > BARの置換)モードで正規表現をサポートします。
  • スワップ(foo - > barとbar - > foo)または一意でない置換のセット(foo - > bar、f - > x)を含む複数の置換で動作します。

それを使うにはpip install repren例としてREADME を確認してください。

25
jlevy

複数のファイル内の文字列を置き換えるには、次のようにします。

grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'

例えば。

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

ソースブログ

24
Djacomo

ファイル内のパスを置き換える(エスケープ文字を避ける)には、次のコマンドを使用します。

sed -i 's@old_path@new_path@g'

@記号は、後続の文字列ではすべての特殊文字を無視する必要があることを意味します。

17

文字列にスラッシュ(/)が含まれている場合は、区切り文字を「+」に変更できます。

find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +

このコマンドは現在のディレクトリで再帰的に実行されます。

12
gopiariv

"foo"の最初の行の出現箇所は "bar"に置き換えられます。そして、2行目を使って確認することができます。

grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
11
jiasir

使用できるファイルのリストがある場合

replace "old_string" "new_string" -- file_name1 file_name2 file_name3

すべてのファイルがある場合は使用できます

replace "old_string" "new_string" -- *

拡張子が付いたファイルのリストがある場合は、次のものを使用できます。

replace "old_string" "new_string" -- *.extension
8
Pawel Dubiel

私はこの質問(と答え)を見つける前に自分の解決策を考案しました。 "replace"、 "several"、および "xml"のさまざまな組み合わせを検索しました。これが私のアプリケーションだったのですが、この特定のものが見つかりませんでした。

私の問題:私は複雑なオブジェクトを含むテストケースのためのデータを含む春のxmlファイルを持っていました。 Javaソースコードのリファクタリングによって多くのクラスが変更され、xmlデータファイルには適用されませんでした。テストケースデータを保存するために、私はいくつかのディレクトリに分散しているすべてのxmlファイルのすべてのクラス名を変更する必要がありました。元のxmlファイルのバックアップコピーを保存している間(バージョン管理ではここに保存されるので、これは必須ではありませんでしたが)。

私はfind + sedの組み合わせを探していましたが、それは他の状況では私にとってはうまくいきましたが、一度にいくつかの置き換えをしてもうまくいきませんでした。

それから私は ubuntuの応答を尋ねる を見つけました、そしてそれは私が私のコマンドラインを構築するのを助けました:

find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

そしてそれは完璧に動作しました(まあ、私の場合は6つの異なる置き換えがありました)。ただし、現在のディレクトリの下にあるすべての* .xmlファイルにアクセスします。そのため、そしてあなたがバージョン管理システムに責任があるならば、あなたは最初にフィルタをかけて、あなたが望む文字列を実際に持っているものだけをsedに渡すことを望むかもしれません。好きです:

find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
4
manuelvigarcia

「findやsedを使うこともできますが、この小さなPerlの行はうまく機能することがわかりました。

Perl -pi -w -e 's/search/replace/g;' *.php
  • -eは次のコード行を実行することを意味します。
  • -iはインプレース編集を意味します
  • -w警告を書く
  • -pループ

"( http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php から抽出)

私の最良の結果はPerlとgrepの使用から来る(そのファイルが検索式を持つことを確実にするために)

Perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
grep --include={*.php,*.html} -rnl './' -e "old" | xargs -i@ sed -i 's/old/new/g' @
3
Dennis

マルチエディットコマンドのスクリプト

multiedit [-n PATTERN] OLDSTRING NEWSTRING

Kasparの答えから、私はコマンドライン引数を受け取り、必要に応じてパターンにマッチするファイル名を制限するためのbashスクリプトを作りました。 $ PATHに保存して実行可能にしてから、上記のコマンドを使用してください。

これがスクリプトです。

#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n

[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"

# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then  # if -n option is given:
        # replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
        find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
        # replace OLDSTRING with NEWSTRING recursively in all files
        find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi
2

本当に残念ですが、sedコマンドをOSX上で正しく動作させることができなかったので、代わりに次のような愚かなことをしました。

:%s/foo/bar/g
:wn

^ - これら3行を私のクリップボードにコピーして(はい、最後の改行を含めて)、それから:

vi *

ファイルがなくなるまでcommand-vを押し続けます。

ダム...ハッキー...効果的な...

2
Justin

私の個人的な英語のノードを維持するために、私はディレクトリの下のすべてのファイルに対して再帰的に古い/新しい文字列の複数の組を置き換えるのを助けるユーティリティスクリプトを書きました。

古い/新しい文字列の複数のペアはハッシュマップで管理されます。

Dirはコマンドラインまたは環境変数で設定できます。マップはスクリプトでハードコードされていますが、必要に応じてファイルからロードするようにコードを変更することもできます。

いくつかの新機能のため、bash 4.2が必要です。

en_standardize.sh:

#! /bin/bash
# (need bash 4.2+,)
# 
# Standardize phonetic symbol of English.
# 
# format:
#   en_standardize.sh [<dir>]
# 
# params:
# * dir
#   target dir, optional,
#   if not specified then use environment variable "$node_dir_en",
#   if both not provided, then will not execute,
# * 
# 

paramCount=$#

# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
    echo -e "dir specified (in command):\n\t$1\n"
    targetDir=$1
Elif [[ -v node_dir_en ]]; then # environable set,
    echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
    targetDir=$node_dir_en
else # environable not set,
    echo "dir not specified, won't execute"
    exit
fi

# check whether dir exists,
if [ -d $targetDir ]; then
    cd $targetDir
else
    echo -e "invalid dir location:\n\t$targetDir\n"
    exit
fi

# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")

# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
    echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'

# do replace,
for key in "${!itemMap[@]}"; do
    grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done

echo -e "\nDone."
exit
1
Eric Wang

MacBook Proでは、次のものを使用しました( https://stackoverflow.com/a/19457213/6169225 からヒントを得たもの)。

sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *

-i ''はバックアップを取っていないことを保証します。

現代の正規表現の場合は-e

1
Marquistador

Ackコマンドを使用すると、次のように速くなります。

ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'

検索結果に空白がある場合も同様です。あなたはそれを脱出する必要があります。

1

-iスイッチを指定して起動すると、ストリームエディタは「インプレース」で複数のファイルを変更します。そう

sed -i.bak 's/foo/bar/g' *

このフォルダ内のすべてのファイルでfoobarに置き換えますが、サブフォルダには降りません。ただし、これにより、ディレクトリ内のすべてのファイルに対して新しい.bakファイルが生成されます。このディレクトリ内のすべてのファイルとそのすべてのサブディレクトリに対してこれを再帰的に行うには、ディレクトリツリーをトラバースするためのfindなどのヘルパーが必要です。

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

必要に応じてfindを使用すると、find ./ -name '*.php' -or -name '*.html' -print0などの引数をさらに指定することで、変更するファイルをさらに制限できます。


注:GNU sedはファイルの末尾を必要としません。sed -i 's/foo/bar/g' *も機能します。 FreeBSDのsedは拡張を必要としますが、間にスペースを入れることができるので、sed -i .bak s/foo/bar/g *は動作します。

1
Anaphory

ファイルにバックスラッシュ(通常はパス)が含まれている場合は、次のようにして試すことができます。

sed -i -- 's,<path1>,<path2>,g' *

例:

sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all Shell scripts available)
1
Shaik Amanulla

私はこれを他の記事から見つけました(どれを思い出せません)が、最も洗練されたものではありませんが、それは単純で初心者のLinuxユーザーとしては何の問題もありません。

for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done

スペースや他の特殊文字がある場合は\を使用してください。

for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done

サブディレクトリ内の文字列には**を使用

for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
0
Kyle Turck

私はPythonソースで一般的なShebangエラーを修正するための例を挙げています。

Grep/sedアプローチを試すことができます。これはGNU sedで動作し、gitリポジトリを壊さないものです:

$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}

または greptile :)を使用できます。

$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .

最初のスクリプトをテストしたところ、2番目のスクリプトも同様に機能するはずです。エスケープ文字には注意してください。ほとんどの場合、greptileを使用する方が簡単なはずです。もちろん、sedを使って面白いことをたくさんすることができます。そのため、xargsを使ってマスターすることをお勧めします。

0
exa

以下のコマンドは、最初にファイルを検索してファイルを置き換えるために使用できます

見つけます。 | xargs grep検索文字列| sedの/検索文字列/新しい文字列/ g '

例えば見つけます。 | xargs grep abc | sedの/ abc/xyz/g '

0
Amit

簡単なスクリプトファイルを使用すると、より簡単な方法があります。

   # Sudo chmod +x /bin/replace_string_files_present_dir

geditまたは選択したエディターでファイルを開きます。ここではgeditを使用します。

   # Sudo gedit /bin/replace_string_files_present_dir

次に、エディターで次をファイルに貼り付けます

   #!/bin/bash
   replace "oldstring" "newstring" -- *
   replace "oldstring1" "newstring2" -- *
   #add as many lines of replace as there are your strings to be replaced for 
   #example here i have two sets of strings to replace which are oldstring and 
   #oldstring1 so I use two replace lines.

ファイルを保存し、geditを閉じてから、ターミナルを終了するか、単に閉じてから追加して、追加した新しいスクリプトをロードできるようにします。

編集する複数のファイルがあるディレクトリに移動します。次に実行します:

  #replace_string_files_present_dir

Enterキーを押すと、oldstringoldstring1が自動的に置き換えられますそれぞれ正しいnewstringおよびnewstring1でそれらを含むファイル。

古い文字列を含まないすべてのディレクトリとファイルをスキップします。

これは、文字列の置換が必要なファイルを含む複数のディレクトリがある場合に、入力の退屈な作業を排除するのに役立つ場合があります。必要なのは、これらの各ディレクトリに移動してから実行するだけです:

#replace_string_files_present_dir

あなたがしなければならないのは、上記で示したように、すべての置換文字列を含めるか追加したことを確認することです。

replace "oldstring" "newstring" -- *

ファイルの最後/ bin/replace_string_files_present_dir

新しい置換文字列を追加するには、ターミナルで次のように入力して作成したスクリプトを開きます。

Sudo gedit /bin/replace_string_files_present_dir

追加する置換文字列の数について心配する必要はありません。oldstringが見つからない場合は効果がありません。

0
briancollins081

文字列searchを検索し、複数のファイルでreplaceに置き換えたい場合、これは バトルテスト済みの1行の式

grep -RiIl 'search' | xargs sed -i 's/search/replace/g'

簡単なgrepの説明:

  • -R-再帰的検索
  • -i-大文字と小文字を区別しません
  • -I-バイナリファイルをスキップします(テキストが必要ですか?)
  • -l-出力として単純なリストを印刷します。他のコマンドに必要

次に、grep出力は(xargsを介して)sedにパイプされ、実際にテキストを置換するために使用されます。 -iフラグは、ファイルを直接変更します。一種の「ドライラン」モードの場合は削除します。

0
Ignorant