複数のパターンを使用するファイルを探したいです。
これは私の元のコマンドです。しかし、入力は非常に長くてxargs zgrep
冗長です。入力するパターンが10個以上の場合はどうなりますか?
find -mtime -$a -type f ! -name "*.bak*" | xargs zgrep -il "$b" | xargs zgrep -il "$c" | xargs zgrep -il "$d" | xargs zgrep -il 'ST.997' | sort -u
たとえば、次のように少ない文字を入力したいとします。
find -mtime -$a -type f ! -name "*.bak*" | xargs zgrep -il "$b && $c && $d" | sort -u
編集する:これらのパターンは$
。これは、コマンドがスクリプト内にあり、これらの変数に文字列/数値があるためです。
私はこれを使ってスクリプト、特にランタイムを改善します。
答え1
各モードでファイルの圧縮を解凍しないようにするには、次のようにします。
PATTERNS='foo
bar
baz' find . -mtime -"$a" -type f ! -name "*.bak*" -exec awk -v q=\' '
function shquote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ENVIRON["PATTERNS"], pats, "\n")
for (arg = 1; arg < ARGC; arg++) {
file = ARGV[arg]
cmd = "gzip -dcf < " shquote(file)
for (i = 1; i <= n; i++) notfound[pats[i]]
left = n
while (left && (cmd | getline line) > 0) {
for (pat in notfound) {
if (line ~ pat) {
if (!--left) {
print file
break
}
delete notfound[pat]
}
}
}
close(cmd)
}
exit
}' {} +
スキーマは次のように処理されます。awk
grep -E
/supported 拡張正規表現に似たパターンですegrep
。大文字と小文字を区別しない一致のために、-v IGNORECASE=1
GNUを使用してifを追加しawk
たり、次のように移植可能に変更したりできます。
PATTERNS='foo
bar
baz' find . -mtime -"$a" -type f ! -name "*.bak*" -exec awk -v q=\' '
function shquote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(tolower(ENVIRON["PATTERNS"]), pats, "\n")
for (arg = 1; arg < ARGC; arg++) {
file = ARGV[arg]
cmd = "gzip -dcf < " shquote(file)
for (i = 1; i <= n; i++) notfound[pats[i]]
left = n
while (left && (cmd | getline line) > 0) {
line = tolower(line)
for (pat in notfound) {
if (line ~ pat) {
if (!--left) {
print file
break
}
delete notfound[pat]
}
}
}
close(cmd)
}
exit
}' {} +
(スキーマに非標準のERE拡張がないと仮定すると(たとえば)\S
に変換されます\s
。
このawk
コマンドをzgrep-many
スクリプトに入れて使いやすくすることができます。それは次のとおりです。
#! /bin/sh -
usage() {
cat >&2 << EOF
Usage: $0 [-e <pattern>] [-f <file] [-i] [pattern] files
List the files for which all the given patterns are matched.
EOF
exit 1
}
ignorecase=
PATTERNS=
export PATTERNS
NL='
'
sep=
while getopts e:f:i opt; do
case $opt in
(e) PATTERNS=$PATTERNS$sep$OPTARG; sep=$NL;;
(f) PATTERNS=$PATTERNS$sep$(cat < "$OPTARG") || exit; sep=$NL;;
(i) ignorecase='tolower(';;
(*) usage;;
esac
done
shift "$((OPTIND - 1))"
if [ -z "$PATTERNS" ]; then
[ "$#" -gt 0 ] || usage
PATTERN=$1; shift
fi
[ "$#" -eq 0 ] && exit
exec awk -v q=\' '
function shquote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split('"$ignorecase"'ENVIRON["PATTERNS"]'"${ignorecase:+)}"', pats, "\n")
for (arg = 1; arg < ARGC; arg++) {
file = ARGV[arg]
cmd = "gzip -dcf < " shquote(file)
for (i = 1; i <= n; i++) notfound[pats[i]]
left = n
while (left && (cmd | getline line) > 0) {
'"${ignorecase:+line = tolower(line)}"'
for (pat in notfound) {
if (line ~ pat) {
if (!--left) {
print file
break
}
delete notfound[pat]
}
}
}
close(cmd)
}
exit
}' "$@"
次のように使用されます。
find ... -exec zgrep-many -ie foo -e bar -e baz {} +
例えば。
答え2
grep
複数のパターンを一致させるにはANDオプションはありませんが、デフォルトではORを使用してパターンを一致させることができます|
。拡張構文を使用している場合は、複数のパターンとすべての組み合わせを組み合わせることができます。
a.*b.*c|a.*c.*b|b.*a.*c|b.*c.*a|c.*a.*b|c.*b.*a
ただし、パターンが2つ以上の場合、組み合わせの数が急速に増加するため、これは良い考えではない可能性があります。
zgrep
を使用してコマンドを結合できます-exec
。最後のオプションを除く-q
すべてのオプションは自動オプションを使用しますzgrep
(見つかったすべての古いgrepと一致する場合はファイル名を印刷します)。
find -mtime -$a -type f ! -name "*.bak*" \
-exec zgrep -iq "$b" {} \; \
-exec zgrep -iq "$c" {} \; \
-exec zgrep -il "$d" {} \; | sort
答え3
find
3つの-sを実行するコマンドを使用できますzgrep
。
find -mtime -$a -type f ! -name "*.bak*" \
-exec zgrep -q {} "$b" \; \
-a -exec zgrep -q {} "$c" \; \
-a -exec zgrep -q {} "$d" \; \
| sort
ファイル名を最初に収集することもできますgrep
。
find -mtime -$a -type f ! -name "*.bak*" > /tmp/file-list
(ファイル名が良好でスペースがないと仮定)
その後、各行を繰り返します。/tmp/file-list
awk
最後に、他の言語(Python、...)でスクリプトを書くことができます。
入力を避けるためにシェル関数を定義できます。