私は、サーバへのアクセスがssh
だけで、フォルダ内のたくさんのファイルの文字列を置き換える必要があります。これどうやってするの?
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
"foo"の出現は "bar"に置き換えられます。
Kasparの答えに似ていますが、行のすべての出現箇所を置き換えるためのgフラグが付いています。
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
グローバルな大文字と小文字を区別しない場合:
find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
@ kevの答えは良いですが、直下のディレクトリにあるファイルにのみ影響します。以下の例では、grepを使ってファイルを再帰的に見つけます。それは私のためにいつも働きます。
grep -rli 'old-Word' * | xargs -i@ sed -i 's/old-Word/new-Word/g' @
これは私のために働いた:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
しかし、これはしませんでした:sed -i 's/string1/string2/g' *
。たぶん、「foo」はstring1であり、「bar」はstring2ではありませんでした。
これに対する既にいくつかの標準的な答えがあります。通常、 find を使用してファイルを再帰的にリストしてから、 sed または Perl を使用して操作を実行できます。
ほとんどの場合、 rpl の方が覚えやすいでしょう。これは置き換え(foo - > bar)で、すべてのファイルに対して再帰的に行われます。
rpl -R foo bar .
おそらくそれをインストールする必要があるでしょう(apt-get install rpl
またはそれに類似したもの)。
しかし、正規表現や後退代入、あるいはファイル名の変更や検索と置換を含むもっと難しい仕事のために、私が知っている最も一般的で強力なツールは Representn 小さなPythonスクリプト私はしばらくの間、いくつかのとんでもない名前の変更とリファクタリングのタスクについて書きました。あなたがそれを好むかもしれない理由は:
それを使うにはpip install repren
。 例としてREADME を確認してください。
複数のファイル内の文字列を置き換えるには、次のようにします。
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
例えば。
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
ファイル内のパスを置き換える(エスケープ文字を避ける)には、次のコマンドを使用します。
sed -i 's@old_path@new_path@g'
@記号は、後続の文字列ではすべての特殊文字を無視する必要があることを意味します。
文字列にスラッシュ(/)が含まれている場合は、区切り文字を「+」に変更できます。
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
このコマンドは現在のディレクトリで再帰的に実行されます。
"foo"の最初の行の出現箇所は "bar"に置き換えられます。そして、2行目を使って確認することができます。
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
使用できるファイルのリストがある場合
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
すべてのファイルがある場合は使用できます
replace "old_string" "new_string" -- *
拡張子が付いたファイルのリストがある場合は、次のものを使用できます。
replace "old_string" "new_string" -- *.extension
私はこの質問(と答え)を見つける前に自分の解決策を考案しました。 "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' {} \;
「findやsedを使うこともできますが、この小さなPerlの行はうまく機能することがわかりました。
Perl -pi -w -e 's/search/replace/g;' *.php
"( 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' @
マルチエディットコマンドのスクリプト
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
本当に残念ですが、sedコマンドをOSX上で正しく動作させることができなかったので、代わりに次のような愚かなことをしました。
:%s/foo/bar/g
:wn
^ - これら3行を私のクリップボードにコピーして(はい、最後の改行を含めて)、それから:
vi *
ファイルがなくなるまでcommand-vを押し続けます。
ダム...ハッキー...効果的な...
私の個人的な英語のノードを維持するために、私はディレクトリの下のすべてのファイルに対して再帰的に古い/新しい文字列の複数の組を置き換えるのを助けるユーティリティスクリプトを書きました。
古い/新しい文字列の複数のペアはハッシュマップで管理されます。
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
MacBook Proでは、次のものを使用しました( https://stackoverflow.com/a/19457213/6169225 からヒントを得たもの)。
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
はバックアップを取っていないことを保証します。現代の正規表現の場合は
-e
。
Ackコマンドを使用すると、次のように速くなります。
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
検索結果に空白がある場合も同様です。あなたはそれを脱出する必要があります。
-i
スイッチを指定して起動すると、ストリームエディタは「インプレース」で複数のファイルを変更します。そう
sed -i.bak 's/foo/bar/g' *
このフォルダ内のすべてのファイルでfoo
をbar
に置き換えますが、サブフォルダには降りません。ただし、これにより、ディレクトリ内のすべてのファイルに対して新しい.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 *
は動作します。
ファイルにバックスラッシュ(通常はパス)が含まれている場合は、次のようにして試すことができます。
sed -i -- 's,<path1>,<path2>,g' *
例:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all Shell scripts available)
私はこれを他の記事から見つけました(どれを思い出せません)が、最も洗練されたものではありませんが、それは単純で初心者の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
私は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を使ってマスターすることをお勧めします。
以下のコマンドは、最初にファイルを検索してファイルを置き換えるために使用できます
見つけます。 | xargs grep検索文字列| sedの/検索文字列/新しい文字列/ g '
例えば見つけます。 | xargs grep abc | sedの/ abc/xyz/g '
簡単なスクリプトファイルを使用すると、より簡単な方法があります。
# 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キーを押すと、oldstringとoldstring1が自動的に置き換えられますそれぞれ正しい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が見つからない場合は効果がありません。
文字列search
を検索し、複数のファイルでreplace
に置き換えたい場合、これは バトルテスト済みの1行の式 :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
簡単なgrepの説明:
-R
-再帰的検索-i
-大文字と小文字を区別しません-I
-バイナリファイルをスキップします(テキストが必要ですか?)-l
-出力として単純なリストを印刷します。他のコマンドに必要次に、grep出力は(xargsを介して)sedにパイプされ、実際にテキストを置換するために使用されます。 -i
フラグは、ファイルを直接変更します。一種の「ドライラン」モードの場合は削除します。