web-dev-qa-db-ja.com

findとsedを使用するときにファイル名を取得する方法

特定のファイルにsedを適用し、変更されたファイルをリストして、変更されたファイルがわかるようにするスクリプトを書いています。

これは私がsedを見つけて使用する方法です:

find . -type f -a \( -name "*.txt" -o -name "*.git"\) -a -exec sed -i -e "s/"str1"/"str2"/g" {} +

変更されたファイルのファイル名を印刷するにはどうすればよいですか?読みやすくするために、並べ替えて印刷したいと思います。

Sedのみを使用する場合、これを行うことができます。

sed -i 's/$pattern/$new_pattern/w changelog.txt' $filename
if [ -s changelog.txt ]; then
  # CHANGES MADE, DO SOME STUFF HERE
else
  # NO CHANGES MADE, DO SOME OTHER STUFF HERE
fi

しかし、findとsedを一緒に使用する場合、どうすればよいですか? manページをチェックして、たくさんのことを試しましたが、何も機能しませんでした。

4
KLMM

sed -iは、sスクリプトのsedコマンドのいずれかが成功したかどうかに関係なく、ファイルを書き換えます(実際にはファイルの完全な新しいコピーを作成します)。

ここでは、sed -iを含まないファイルでstr1を実行することは避けたいと思います。 GNUツールを使用:

find . -type f \( -name "*.txt" -o -name "*.git" \) -size +3c \
  -exec grep -lZ str1 {} + |
  while IFS= read -rd '' file; do
    sed -i 's/str1/str2/g' "$file" &&
      printf '%s\n' "$file"
  done

これは、str1を含むファイルごとに1つのsedを実行し、sedが成功した場合(新しいバージョンの作成でエラーが発生しなかった場合)にファイル名を出力します。ファイル)。

または、ファイルごとに1つのgrepsedを実行できます。

find . -type f \( -name "*.txt" -o -name "*.git" \) \( -size +3c \
  -exec grep -q str1 {} \; \
  -exec sed -i 's/str1/str2/g' {} \; \
  -printf '"%p" was modified\n' \
    -o -printf '"%p" was not modified\n"' \)
1

sedコマンド(適切な引用符付き):

sed 's/str1/str2/g'

これにより、str1のすべての出現箇所がstr2に変更されます。 str1を含むファイルのリストはgrep -l 'str1'から取得できます。

find . -type f \( -name '*.txt' -o -name '*.git' \) \
    -exec grep -l 'str1' {} \; \
    -exec sed -i 's/str1/str2/g' {} + >changelist.txt

ここで、grep -lは、changelist.txtにリダイレクトされるパス名のリストを提供します。また、sedのフィルターのように機能するため、sedはパターンを含むファイルでのみ実行されます。 sed -iはファイルに変更を加えます(そして静かなままです)。

または、findに文字列を含むファイルのパス名を出力させます。

find . -type f \( -name '*.txt' -o -name '*.git' \) \
    -exec grep -q 'str1' {} \; \
    -print \
    -exec sed -i 's/str1/str2/g' {} + >changelist.txt

関連:

0
Kusalananda

必要なことを実行する小さなスクリプトを記述し、execへの引数としてスクリプトをfind書くのは簡単です。すでにスクリプトがあり、$filename$1に置き換えると、スクリプトができます。スクリプトは次の形式になります

#!/bin/bash
sed -i 's/$pattern/$new_pattern/' $1
echo $1 >> changelog

このスクリプトをed_notifyと呼びましょう。これで、選択したファイルで実行できます。

cat changelog >> changelog.old
rm changelog
find . -type f -a \( -name "*.txt" -o -name "*.git"\) -a -exec ed_notify {} \;
0
unxnut