次のコマンドは、2つのファイルの内容を正しく変更しています。
sed -i 's/abc/xyz/g' xaa1 xab1
しかし、私がする必要があるのは、そのようなファイルを動的に変更することであり、ファイル名がわかりません。私は始まる、現在のディレクトリからすべてのファイルを読み込みますコマンド書きたいxa*
とsed
、ファイルの内容を変更する必要があります。
次のコマンドは、2つのファイルの内容を正しく変更しています。
sed -i 's/abc/xyz/g' xaa1 xab1
しかし、私がする必要があるのは、そのようなファイルを動的に変更することであり、ファイル名がわかりません。私は始まる、現在のディレクトリからすべてのファイルを読み込みますコマンド書きたいxa*
とsed
、ファイルの内容を変更する必要があります。
回答:
さらに良い:
for i in xa*; do
sed -i 's/asd/dfg/g' $i
done
ファイルがいくつあるか誰も知らないため、コマンドラインの制限を破るのは簡単です。
ファイルが多すぎると、次のようになります。
# grep -c aaa *
-bash: /bin/grep: Argument list too long
# for i in *; do grep -c aaa $i; done
0
... (output skipped)
#
for
。find ... | xargs ...
for
、それがためよりもecho
かgrep
?
"$i"
代わりに$i
を使用して、スペースを含むファイル名の単語分割を回避する必要があります。そうでなければ、これはとてもいいです。
for
言語構文の一部であり、単なる組み込みではないということです。の場合sed -i 's/old/new' *
、の展開は*
sedの引数リストとして渡される必要があり、sed
プロセスを開始する前にこれを実行する必要があると確信しています。for
ループを使用すると、完全なarglist(の展開*
)がコマンドとして渡されることはなく、シェルメモリに格納されて繰り返されるだけです。私はこれについてはまったく言及していませんが、それが違いである可能性が高いようです。(もっと知識のある人から連絡をもらいたい...)
一致するファイル名ごとにプロセスを開始しますが、このタイプのユースケースを対象とする-exec引数について誰も言及していないことに驚いています。
find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} \;
あるいは、より少ないプロセスを呼び出すxargsを使用することもできます。
find . -type f -name 'xa*' | xargs sed -i 's/asd/dsg/g'
または、findの代わりに+
execバリアントを使用して;
、findがサブプロセス呼び出しごとに複数のファイルを提供できるようにします。
find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} +
find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;
が、findコマンドの場所であり、OSXの./
後-i
には単一引用符のペアです。
./
と同じように機能します。これは、backupsuffixパラメーター.
と同じであり、その後-i
にパラメーターのみが含まれます。
-exec
一緒に検索のオプションが{} +
述べたように問題を解決するのに十分であり、最も要件の罰金にする必要があります。ただしxargs
、-p
オプションで並列処理もできるため、一般的にはより良い選択です。コマンドラインの長さをオーバーフローするのに十分な大きさのグロブ拡張がある場合、シーケンシャル実行よりもスピードアップの恩恵を受ける可能性があります。
grepとsedを一緒に使用できます。これにより、サブディレクトリを再帰的に検索できます。
Linux: grep -r -l <old> * | xargs sed -i 's/<old>/<new>/g'
OS X: grep -r -l <old> * | xargs sed -i '' 's/<old>/<new>/g'
For grep:
-r recursively searches subdirectories
-l prints file names that contain matches
For sed:
-i extension (Note: An argument needs to be provided on OS X)
grep -v
gitフォルダーを回避するために私が陥ることができたということでしたgrep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
これらのコマンドsed
は、Mac OS Xに付属するデフォルトでは機能しません。
からman 1 sed
:
-i extension
Edit files in-place, saving backups with the specified
extension. If a zero-length extension is given, no backup
will be saved. It is not recommended to give a zero-length
extension when in-place editing files, as you risk corruption
or partial content in situations where disk space is exhausted, etc.
試しました
sed -i '.bak' 's/old/new/g' logfile*
そして
for i in logfile*; do sed -i '.bak' 's/old/new/g' $i; done
どちらも正常に動作します。
@PaulRはこれをコメントとして投稿しましたが、人々はそれを回答として見る必要があります(そしてこの回答は私のニーズに最適です):
sed -i 's/abc/xyz/g' xa*
これは、おそらく数十程度の適度な量のファイルで機能しますが、数百万程度ではありません。
sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn
。
別のより用途の広い方法は使用することfind
です:
sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')
find
同様のタスクに使用しています。これは非常に簡単です。次のsed
ように引数として渡す必要があります。
sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`
この方法では、複雑なループを記述する必要がなく、変更するファイルを確認するのは簡単find
ですsed
。実行する前に実行するだけです。
あなたは作ることができます
' xxxx ' text u search and replace it it with ' yyyy '
grep -Rn '**xxxx**' /path | awk -F: '{print $1}' | xargs sed -i 's/**xxxx**/**yyyy**/'
スクリプトを実行できる場合は、同様の状況で私が行ったことを次に示します。
sed
コマンドに辞書/ハッシュマップ(連想配列)と変数を使用して、配列をループし、いくつかの文字列を置き換えることができます。ワイルドカードをに含めると、name_pattern
ファイルのインプレースをname_pattern='File*.txt'
特定のディレクトリ(source_dir
)内のパターン(のようなもの)に置き換えることができます。すべての変更はlogfile
、destin_dir
#!/bin/bash
source_dir=source_path
destin_dir=destin_path
logfile='sedOutput.txt'
name_pattern='File.txt'
echo "--Begin $(date)--" | tee -a $destin_dir/$logfile
echo "Source_DIR=$source_dir destin_DIR=$destin_dir "
declare -A pairs=(
['WHAT1']='FOR1'
['OTHER_string_to replace']='string replaced'
)
for i in "${!pairs[@]}"; do
j=${pairs[$i]}
echo "[$i]=$j"
replace_what=$i
replace_for=$j
echo " "
echo "Replace: $replace_what for: $replace_for"
find $source_dir -name $name_pattern | xargs sed -i "s/$replace_what/$replace_for/g"
find $source_dir -name $name_pattern | xargs -I{} grep -n "$replace_for" {} /dev/null | tee -a $destin_dir/$logfile
done
echo " "
echo "----End $(date)---" | tee -a $destin_dir/$logfile
まず、ペアの配列が宣言され、各ペアは、置換文字列で、その後WHAT1
のために置換されますFOR1
とOTHER_string_to replace
のために置換されますstring replaced
ファイルにFile.txt
。ループでは配列が読み取られ、ペアの最初のメンバーはreplace_what=$i
として、2番目のメンバーはとして取得されreplace_for=$j
ます。このfind
コマンドは、ディレクトリ内でファイル名(ワイルドカードを含む場合があります)を検索し、sed -i
以前に定義されたものと同じファイル内で置き換えます。最後に、grep
リダイレクトされたログファイルを追加して、ファイルに加えられた変更をログに記録しました。
これは私にとってGNU Bash 4.3
sed 4.2.2
うまくいき、bashのタプルのループに対するVasyaNovikovの回答に基づいています 。
sed -i 's/abc/xyz/g' xa*
?