次の場合にのみ、すべてのサブディレクトリのすべてのファイルの先頭にテキストを配置するbashスクリプトを作成しようとしています。
- ファイルにテキストが含まれていません。
- ファイルには、会社名、Riverという単語、またはSystemsという単語が含まれています。
これが私が今まで持っているものです:
for i in $(find -name *.cpp -type f -print)
do
if ! grep -r 'This document contains technical data' $i && grep -r 'company name' $1 || grep-r 'River' $i || grep -r 'Systems' $i; then
#add text
これで、キーワードが含まれていないファイルは期待どおりに変更されませんが、テキストとキーワードがすでに含まれているファイルの場合は変更されます。 ||周りに[]ステートメントを使用してみましたが、結果は同じです。どんな提案がありますか?
答え1
find . -name '*.cpp' -type f \
! -exec grep -qF 'This document contains technical data' {} ';' \
-exec grep -qFe River -e 'company name' -e Systems {} ';' \
-exec sed -i '1i\
This document contains technical data' {} +
(FreeBSD / macos 'sed -i
に置き換えられます)sed -i ''
sed
grep
あるいは、GNUを使用すると、GNUはより効率的ですxargs
。
grep --include='*.cpp' -rFlZ -e River -e 'company name' -e Systems . |
xargs -r0 grep -FLZ 'This document contains technical data' |
xargs -r0 sed -i '1i\
This document contains technical data.'
試みに関するいくつかの注意:
find -print
出力を後処理できません。。- パラメータ拡張は、以下で引用する必要があります。
bash
-r
(GNU拡張)再帰的grep は、独自のタスクに加えて他のタスクをgrep
実行するには、ディレクトリを ping するときにのみ使用できます (ディレクトリからファイルを検索し、そのファイルでパターンを探します)。find
grep
*
特殊文字シェル、そこからワイルドカードがトリガされます。*.cpp
にリテラルを渡すことができるように引用されていることを確認する必要がありますfind
。- 一致するすべての行をチェックせずにファイル内のパターンが一致できるかどうかを確認するには、このオプションを使用します
-q
。印刷をスキップするだけでなく、grep
最初の一致を確認しないので、より効率的です。(GNU拡張)は同じ最適化を持っています-l
。-L
前者は、パターンが見つかるとファイルパスを印刷し、後者はパターンが見つからない場合はファイルパスを印刷します。 - 固定文字列を検索するには
F
(正規表現マッチングを実行するのではなく)、この-F
オプションを使用して正規表現演算子をエスケープする必要はありません。 - 、を
grep foo file || grep bar file
使用せずに1つのパターンで複数のパターンを見つけることができます。find
'(' -exec grep -q foo {} ';' -o -exec grep -q bar {} ';' ')'
grep
または一度にスタイリッシュgrep -e foo -e bar file
に他の方法。 - orとも
grep -F River
一致しますRiverside
。一致するオプションのみを追加できます。WindRiver
-w
みんな単語(単語は数字や下線などの単語以外の文字で区切る必要があり、単語以外の文字はその他の文字です)。
答え2
&&を別のifステートメントに置き換えると、次のように動作します。
if ! grep -r 'This document contains technical data' $i; then
if grep -r 'company name' $1 || grep-r 'River' $i || grep -r 'Systems' $i; then
#add text
fi
fi