Неважно просто используйте pcregrep
как предложено @StephaneChazelas.
Это должно работать:
$ find . -name "*.cpp" |
while IFS= read -r file; do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Идея состоит в том, чтобы использовать grep's -A
переключитесь для вывода подобранных строк и N после строк. Вы затем передаете результат через a grep Bar
и если это не соответствует (выход> 0), то Вы повторяете название файла.
Если Вы знаете, что у Вас есть нормальные имена файлов (никакие пробелы, новые строки или другие странные символы), можно упростить до:
$ for file in $(find . -name "*.cpp"); do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Например:
terdon@oregano foo $ cat a.cpp
1 Foo
2 qwerty
3 qwerty
terdon@oregano foo $ cat b.cpp
1 Foo
2 Bar
3 qwerty
terdon@oregano foo $ cat c.cpp
1 Foo
2 qwerty
3 qwerty
4 qwerty
5. Bar
terdon@oregano foo $ for file in $(find . -name "*.cpp"); do grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; done
./c.cpp
./a.cpp
Отметьте это c.cpp
возвращается несмотря на содержание Bar
потому что строка с Bar
больше чем 3 строки после Foo
. Вы cna управляют количеством строк, которые Вы хотите искать путем изменения значения, передали -A
:
$ for file in $(find . -name "*.cpp"); do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
./a.cpp
Вот более короткий (предполагающий, что Вы используете bash
):
$ shopt -s globstar
$ for file in **/*cpp; do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
Как Stephane Chazelas указал в комментариях, вышеупомянутые решения также распечатают файлы, которые не содержат Foo
вообще. Этот избегает что:
for file in **/*cpp; do
grep -qm 1 Foo "$file" &&
(grep -A 3 Foo "$file" | grep -q Bar || echo "$file");
done
- Радиолист
нуждается в двух переменных, а не один. Как объяснено в диалоговом окне MAN
:
--radiolist text height width list-height [ tag item status ] ...
A radiolist box is similar to a menu box. The only difference is
that you can indicate which entry is currently selected, by setting
its status to on.
Как вы можете видеть выше, ему нужны как тег , так и элемент, а также статус. Вот почему это терпит неудачу, когда вы даете ему только один (даже если этот один расширяется до массива).
Вы все еще можете использовать массив, но вам нужно сделать что-то вроде этого:
#!/bin/bash
ch=( "1" "Fri, 20/3/15" "2" "Sun, 21/6/15" "3" "Wed, 23/9/15"
"4" "Mon, 21/12/15")
dialog --title "Equinoxes and Solistices" \
--radiolist "When is the Winter Solictice?" 15 60 4 \
"${ch[0]}" "${ch[1]}" ON \
"${ch[2]}" "${ch[3]}" OFF \
"${ch[4]}" "${ch[5]}" OFF \
"${ch[6]}" "${ch[7]}" OFF 2>/tmp/menu.sh.$$
Я как раз работал над немного более запутанным случаем.
Как Тео спрашивает выше, я использовал автозаполнение вариантов в цикле. Экранирование пробелов в оболочке может быть непростым делом, вот что я сделал.
local LIST=()
for item in *.sh; do
local DESC="$( grep "DESCRIPTION=" $item | sed 's|^DESCRIPTION=||' )"
LIST+=( $( basename $item .sh ) "$DESC" off )
done
local script
script=$( dialog --backtitle "NextCloudPi configuration" \
--radiolist "Select program to configure and activate:" 20 80 10 \
"${LIST[@]}" \
3>&1 1>&2 2>&3 )
echo "$script was selected"
$ DESC
- это переменная оболочки, которая обычно содержит пробелы, и это усложняет этот пример. Как мне сделать так, чтобы диалоговое окно отличало пробелы в $ DESC
от пробелов для разделения его параметров?
Я решил использовать массивы, так как это более естественный подход, позволяющий избежать подобных проблем в любом случае.
Вы можете увидеть полный код и результат в
https://ownyourbits.com/2017/03/05/generic-software-installer-for-raspbian/
Подробнее о массивах и разделении пространства см.