status="curl \"${server}:${port}\"" >/tmp/tmp.txt
host_check='grep "<html" /tmp/tmp.txt'
По крайней мере, его можно упростить до:
set -f # needed if you're using the split+glob operator and don't want the
# glob part
for key in $(cat /tmp/listOfKeys.txt); do
grep -riFqe "$key" . ||
printf '%s\n' "$key has no occurrence"
done
Что прекратит поиск после первого появления ключа
и не будет рассматривать ключ как регулярное выражение (или возможный вариант grep
).
Чтобы избежать необходимости читать файлы несколько раз, и предполагая, что ваш список ключей - это один ключ на строку (в отличие от разделения пробелом/табом/новой строкой в приведенном выше коде), вы можете обойтись инструментами GNU:
find . -type f -size +0 -printf '%p\0' | awk '
ARGIND == 2 {ARGV[ARGC++] = $0; next}
ARGIND == 4 {a[tolower($0)]; n++; next}
{
l = tolower($0)
for (i in a) if (index(l, i)) {
delete a[i]
if (!--n) exit
}
}
END {
for (i in a) print i, "has no occurrence"
}' RS='\0' - RS='\n' /tmp/listOfKeys.txt
Он оптимизирован в том смысле, что перестанет искать ключ
, как только увидит его, и остановится, как только все ключи будут найдены, и прочитает файлы только один раз.
Предполагается, что ключи уникальны в listOfKeys.txt
. Он выводит ключи в нижнем регистре.
Приведенные выше GNUизмы - это -printf '%p\0'
, ARGIND
и способность awk
обрабатывать записи с разделителями NUL. Первые две проблемы можно решить с помощью:
find . -type f -size +0 -exec printf '%s\0' {} + | awk '
step == 1 {ARGV[ARGC++] = $0; next}
step == 2 {a[tolower($0)]; n++; next}
{
l = tolower($0)
for (i in a) if (index(l, i)) {
delete a[i]
if (!--n) exit
}
}
END {
for (i in a) print i, "has no occurrence"
}' step=1 RS='\0' - step=2 RS='\n' /tmp/listOfKeys.txt step=3
Третью можно решить с помощью трюков вроде этого, но это, вероятно, не стоит усилий. Смотрите решение Barefoot IO, чтобы обойти проблему полностью.
GNU grep (как и большинство известных мне вариантов) предлагает опцию -f
, которая делает именно то, что вам нужно. Вариант fgrep
рассматривает входные строки как обычные строки, а не как regex'ы.
fgrep -rio -f /tmp/listOfKeys.txt .
А если вы просто хотите проверить, найдено ли хотя бы одно совпадение, добавьте опцию -q
. По замечанию Стефана, если вам нужно знать, какие строки были не найдены, добавьте опцию -h
и затем передайте через эту обычную идиому awk:
fgrep -h -rio -f /tmp/listOfKeys.txt . |
awk '{$0=tolower($0)}; !seen[$0]++' |
fgrep -v -i -x -f - /tmp/listOfKeys.txt
Второй fgrep
теперь использует результат первого fgrep
(уникальный случай нечувствителен), инвертирует смысл и показывает несовпадающие строки из ключевого файла.
Портативный, POSIX-совместимый перевод подхода gawk Стефана Шазеласа:
find . -type f -exec cat {} + |
awk '
FNR==NR {keys[tolower($0)]; n++; next}
{
s = tolower($0)
for (k in keys)
if (index(s, k)) {
delete keys[k]
if (!--n)
exit
}
}
END {
for (k in keys) print k, "has no occurrence"
}
' /tmp/listOfKeys.txt -
Если только ваши исходные файлы не необычны, в том смысле, что их имена постоянно длиннее их содержимого, решение Стефана должно быть более эффективным, потому что меньше данных передается по трубопроводу (что включает копирование между буферами в двух процессах через ядро).