web-dev-qa-db-ja.com

特定のファイル拡張子を検索してディレクトリを整理する

たとえば、私はディレクトリAにいて、Aの下には多くのフォルダ(B、C、Dなど)があり、各フォルダにはファイル「* .out」とサブフォルダがあります。 * .outファイルでテキスト「index123」を検索し、対応するすべてのフォルダー名を出力するスクリプトをAから実行したいと思います。

これが私のスリップです:

#!/bin/sh  
FILES=home/A  
grep --include=\*.out -rnw $FILES -e "index123" | while read file; do  
str1="FILES/$(basename $file)"  
echo $str1
done

これはエラーを示しています。

N.B.これは、1行のコードで「検索」することで実行できますが、表示されているwhileループにエラーが表示されるのはなぜですか。

1
Akand

投稿からのように whileループで特定の検索を介してファイルを検索 解決策の1つは、whileループを使用して次のようになります。

#!/bin/bash
while IFS= read -r d;
grep -q "index123" "$d" && dirname "$d"|awk -F'/' '{print $2}'
done < <(find . -maxdepth 2 -type f -name "*.out")

1
Akand

次のようなディレクトリ構造を想定しています。

A
|-- B
|   |-- file1.out
|   |-- file2.out
|   `-- file3.out
|-- C
|   |-- file1.out
|   |-- file2.out
|   `-- file3.out
|-- D
|   |-- file1.out
|   |-- file2.out
|   `-- file3.out
`-- E
    |-- file1.out
    |-- file2.out
    `-- file3.out

コードの問題は、grepが次のような出力を生成することです。

./B/file1.out:2:some data which includes the Word index123
./B/file2.out:2:some data which includes the Word index123
./B/file3.out:2:some data which includes the Word index123
./C/file1.out:2:some data which includes the Word index123
./C/file2.out:2:some data which includes the Word index123
./C/file3.out:2:some data which includes the Word index123
./D/file1.out:2:some data which includes the Word index123
./D/file2.out:2:some data which includes the Word index123
./D/file3.out:2:some data which includes the Word index123
./E/file1.out:2:some data which includes the Word index123
./E/file2.out:2:some data which includes the Word index123
./E/file3.out:2:some data which includes the Word index123

それはの出力です

grep --include=\*.out -rnw . -e "index123"

現在のディレクトリとしてAを使用します。

次に、これらの個々の行でbasenameを実行しようとしますが、basenameは最大2つの引数(パス名とそのパス名から削除するサフィックス)を受け取るため失敗します。 GNU basenameは「余分なオペランド」について文句を言いますが、BSD basenameは誤った使用法について文句を言います。


grepは、-lフラグとともに使用すると、ファイルの名前を表示します(つまり、一致した完全な行ではありません)。

これは、スクリプトが単一のコマンドに置き換えられる可能性があることを意味します

grep -w -l "index123" */*.out

これにより、フォームに出力が表示されます

B/file1.out
B/file2.out
B/file3.out
C/file1.out
C/file2.out
C/file3.out
D/file1.out
D/file2.out
D/file3.out
E/file1.out
E/file2.out
E/file3.out

grepコマンドラインで使用したように-wを追加しました。 -n(これも使用している行の番号付け用)は、-lと一緒に使用することはできません。

あなたのコードから判断すると、これはあなたが望むものです。

フォルダ名だけが必要な場合は、

$ grep -w -l "index123" */*.out | sed 's#/[^/]*##' | sort -u
B
C
D
E

これはすべて、Aが現在の作業ディレクトリであることを前提としていますが、これは問題のケースであるとおっしゃっていたので、問題にはならないはずです。

2
Kusalananda