Это самое короткое решение из всех предложенных.
find . -type f -exec perl -lne '
/Some string/i and /other string/ and print($ARGV),close(*ARGV);
' {} +
grep -irZ "Some string" . |
perl -lsF'/\n/' -0ne '
s/^/\n/ if $. == 1; s/$/\n/ if eof;
$. == 1 and $prev = $F[1],next;
push @{$h{$prev}}, $F[0];
$prev = $F[1];
END {
grep($_ =~ /\Q${str2}/, @{$h{$_}}) and print for keys %h;
}
' -- -str2="Another string"
Принцип работы:
Здесь первый grep
выполняет рекурсивный
, нечувствительный к регистру
поиск «какой-то строки» в текущем каталоге и вниз и генерирует нулевой разделитель( \0
) записей из-за опции -Z
, заданной для grep
.
Каждая из этих записей содержит имя файла и совпавшую строку. Единственная загвоздка в том, что порядок не соответствует шагу из-за того, что grep не ставит \0
после соответствующей строки. Чтобы обойти это ограничение, мы используем Perl
, читающий записи, разделенные нулями, и разделяющий эти записи на \n
, чтобы отделить строки от имен файлов.
Следовательно, нет никаких ограничений на типы имен файлов, которые могут быть задействованы, за исключением \0
, которые в любом случае запрещены.
Вы читаете в массив пустую строку. Массив сбрасывается, а затем его первый элемент устанавливается в пустую строку.
Пустая строка — это вполне корректный фрагмент данных. Я не уверен, чего вы ожидали.
Эквивалентный набор команд будет
unset arr
arr[0]=""
arr
теперь представляет собой массив с одним элементом. Его элементом является пустая строка.
Просто комментарий :разница между bash и ksh
$ ksh -c 'read -A a <<<""; typeset -p a'
typeset -a a=('')
$ bash -c 'read -a a <<<""; declare -p a'
declare -a a='()'