В качестве альтернативы ответу Балу Мохана, можно навести порядок шаблонов, используя только grep
, head
и tail
:
for f in FILEGLOB; do tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep "pattern2" &>/dev/null && echo $f; done
Хотя это не очень красиво. Форматируется более наглядно:
for f in FILEGLOB; do
tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null \
| grep -q "pattern2" \
&& echo $f
done
Это напечатает имена всех файлов, где "pattern2"
появляется после "pattern1"
, или где оба появляются в одной строке :
$ echo "abc
def" > a.txt
$ echo "def
abc" > b.txt
$ echo "abcdef" > c.txt; echo "defabc" > d.txt
$ for f in *.txt; do tail $f -n +$(grep -n "abc" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep -q "def" && echo $f; done
a.txt
c.txt
d.txt
Объяснение
tail -n +i
- печатать все строки после i
th включительно
grep -n
- предварительно сопоставлять совпадающие строки с их номерами
head -n1
- печатать только первый ряд
cut -d : -f 1
- вывести первый вырезанный столбец, используя :
в качестве разделителя
2>/dev/null
- тишина tail
ошибка вывода, которая возникает, если выражение $()
возвращает пустое
grep -q
- заставить замолчать grep
и немедленно вернуться, если совпадение найдено, поскольку нас интересует только код выхода