Список файлов, которые не содержат конкретной строки на конкретной строке

! (Шаблон) - это синтаксис ksh glob, в zsh , вы используете ^ (шаблон) , чтобы отменить соответствие, когда extendedglob включен:

setopt extendedglob
print -rl -- ^(2test|3test)

Если вы хотите использовать синтаксис ksh , вам необходимо включить kshglob :

setopt kshglob
print -rl -- !(2test|3test)

Вы также можете использовать and-not / кроме оператора :

setopt extendedglob
print -rl -- *test~[23]*

( * test , кроме файлов, начинающихся с 2 или 3 ).

Также нет, если не включена опция nobareglobqual или вы не используете в них | , конечные операторы группировки (...) конфликтуют с glob квалификаторы. Например, в ! (Foo) или ^ (foo) , foo будет рассматриваться как квалификатор glob. Вам понадобится ^ foo или ! (Foo) (# q) ( (# q) добавляет неоткрытый (явный) квалификатор glob) .

0
15.09.2018, 21:28
5 ответов
find. -type f -name '*.md' -exec \
  sh -c 'sed 1d\;q "$1" | grep -qvx "author: Mr. Xab Ycd"' sh {} \; -print

Вышеупомянутая команда включает все требования без необходимости передачи потенциально -запутанных имен файлов через каналы оболочки.

Первая часть скопирована как -это (почти )из вашего --ищите файлы с именем *.md. Я изменил двойные -кавычки на «жесткие» одинарные -кавычки; в вашем случае нет функциональной разницы, но если вы хотите найти файлы с именем *.$md, то двойные кавычки -попытаются расширить переменную $md.

Совпадающие имена файлов затем проходят еще один тест через -exec. Параметр exec представляет собой небольшой сценарий оболочки, задачей которого является определение успешного или неудачного выполнения данного имени файла в $1. Команда sedпечатает только вторую строку; есть разные способы сделать это, например:

  • sed -n '2{p;q;}'или
  • sed '1d;q

Первый говорит: «Не печатать строки по умолчанию, но когда вы увидите вторую строку, напечатайте ее и закройте». Второй говорит: «печатать строки по умолчанию, но удалить первую строку, после чего выйти (на второй строке ); команда qперед выходом напечатает текущий буфер.

Эта строка текста (, если таковая имеется, )передается команде grep, которая проверяет, соответствует ли вся строка (или нет )заданному тексту. Если не соответствует (-v), то вся команда выполняется успешно и, таким образом, findпечатает имя файла.

2
28.01.2020, 02:18

Я считаю, что awkэто правильный инструмент для работы, но я не знаю Awk . Тем не менее, следующий ответ работает с использованием Bash с включенным параметром оболочки globstar(shopt -s globstar).

prompt% awk 'FNR==2 {print FILENAME, $0}' **/*.md | grep -v 'author: Mr. Xab Ycd' | cut -f1 -d ' '

awkотображает вторую строку всех файлов с именем *.mdв текущем каталоге или в подкаталогах, а grepотфильтровывает имена файлов, не содержащие указанную строку.

0
28.01.2020, 02:18
find. -type f -name '*.md' -exec awk '
    FNR == 2 && $0 == "author: Mr. Xab Ycd" { exit 1 }
    FNR >  2 { exit 0 }' {} ';' -print

Это будет использовать awkдля фильтрации любого файла, который имеет длину не менее двух строк и имеет вторую строку, которая является именно той строкой, которую вы упомянули. Это достигается путем явного выхода с ненулевым -статусом выхода, если вторая строка(FNR == 2)в точности совпадает со строкой. Он также завершается с нулевым статусом выхода, если достигает любой строки после второй, чтобы не анализировать больше, чем необходимо.

Команда findпродолжит печать пути к файлу с помощью -print, если awkзавершается с нулевым статусом выхода (, строка не найдена во второй строке ).

1
28.01.2020, 02:18

Сzsh:

by_Xab() {
  local line
  {
    IFS= read -r line &&
      IFS= read -r line &&
      [[ $line = "author: Mr. Xab Ycd" ]]
  } < ${1-$REPLY}
}
printf '%s\n' **/*.md(D.^+by_Xab)

При этом считывается не более 2 строк для каждого файла и не выполняется ни одна команда (это все встроенные функции ), поэтому будет намного эффективнее, чем find -execподходы, выполняющие одну команду или более для каждого файла.

С помощью GNU awkвы можете сделать:

STRING='author: Mr. Xab Ycd' find. -name '*.md' -type f -exec gawk '
  BEGINFILE {found = 0}
  FNR == 2  {found = $0 == ENVIRON["STRING"]; nextfile}
  ENDFILE   {if (!found) print FILENAME}' {} +

Который будет запускать один findвызов и с синтаксисом -exec... {} +как можно меньше gawkвызовов.

1
28.01.2020, 02:18

Когда findпредоставляет по одному файлу за раз, а бремя печати лежит наfind:

find. -type f -exec perl -lne '$. == 2 && exit +/^author: Mr\. Xab Ycd$/' {} \; -print

здесь findпредоставляет файлы в связке, а задача печати обрабатываетсяperl:

find. -type f -size 0 -print -o -exec perl -lne '
   print $ARGV if $. == 2 && !/^author: Mr\. Xab Ycd$/;
   close(ARGV),next if $. == 2;
   print($ARGV),close(ARGV) if eof;
' {} +

Закрытие-отключение от ARGV необходимо OTW счетчика строк, также известного как $. не инициализируется для предстоящего файла.

Обратите внимание, что условие eof необходимо, так как OTW 2-я строка никогда не будет достигнута для файлов длиной > 1, а проверка 2-й строки никогда не произойдет.

0
28.01.2020, 02:18

Теги

Похожие вопросы