sed :иметь диапазон, заканчивающийся последним вхождением шаблона (жадный диапазон)

Команда updatedbпросканирует файловые системы в вашей системе и создаст индекс имен доступных файлов и каталогов. Эта индексация выполняется от имени непривилегированного пользователя -. Это означает, что индекс всегда будет содержать только имена файлов, которые доступны всем пользователям системы.

Поскольку ваш домашний каталог доступен только вам, (вы говорите в комментариях, что у вас есть rwx------разрешения на него ), это означает, что он не будет проиндексирован пользователем updatedb. Это, в свою очередь, означает, что locateникогда не будет возвращать имена из вашего домашнего каталога. (использование sudo locateвместо простого locateпо-прежнему будет запрашивать тот же индекс, так что это не поможет ).

Чтобы решить эту проблему, у вас есть два варианта:

  1. Ослабьте ограничения для вашего домашнего каталога (и для любого каталога ниже того, который вы хотите проиндексировать,updatedb). Права доступа, вероятно, должны читаться как rwxr-xr-xили 755 в восьмеричном формате.

  2. Не используйте locateдля поиска файлов.Вместо этого используйтеfind:

    find "$HOME" -name test.txt
    

    Это будет искать что-либо с именем test.txtв вашем домашнем каталоге или под ним.

9
13.09.2021, 09:54
4 ответа

Вы можете собрать все строки, начиная со строки abcв резервном пространстве, а затем использовать жадный характер .*, чтобы удалить все после последнейmno:

sed '/abc/,$!d;H;$!d;x;s/\n//;s/\(.*mno[^\n]*\).*/\1/'
  • /abc/,$!ddудалить все до первой abcстроки (или весь файл,если строки abcвообще нет)
  • H;$!dэто классический шаблон для сбора всего файла в области хранения (обратите внимание, что это может быть проблемой для очень больших файлов)
  • мы xменяем буферы вместо использования g, чтобы избежать копирования большого буфера
  • s/\n//удаляет неправильную новую строку в начале, созданную добавлением к пустому пространству хранения
  • s/\(.*mno[^\n]*\n\).*/\1/удаляет все после последнейmnoстроки (или печатает весь оставшийся файл, если строки mnoнет, как запрошено ). Обратите внимание, что [^\n]не является POSIX и будет работать только в некоторых версиях, таких как GNU sed.
2
13.09.2021, 13:02

Использование Raku (, ранее известного как Perl _6)

raku -e '(S:g/ <( ^.*? $$ \n )> ^^.*? abc.*? $$ // andthen S:g/ ^^.* mno.*? $$  <(.*? $)> //).put for lines.join("\n");'

Пример ввода:

1. stu vwx yza
2. uvw xyz abc
3. abc def ghi
4. def ghi jkl
5. ghi jkl mno
6. jkl mno pqr
7. mno pqr stu
8. pqr stu vwx
9. stu vwx yza
10. mno pqr stu
11. xyz xyz xyz

Пример вывода:

2. uvw xyz abc
3. abc def ghi
4. def ghi jkl
5. ghi jkl mno
6. jkl mno pqr
7. mno pqr stu
8. pqr stu vwx
9. stu vwx yza
10. mno pqr stu

Обратите внимание, выше, что Sample Output – это возврат строк со 2 -по -10 при подаче 11-строчного Sample Input. Кроме того, когда образец ввода усекается только до строк с 1 -по -10 (, то есть с mnoв последней строке ), приведенный выше код Raku по-прежнему (правильно )возвращает строки. 2 -- -10.

Спасибо @ImHere и @ChennyStar за то, что подтолкнули меня в комментариях придумать более надежное решение Raku.

https://raku.org

1
14.09.2021, 22:58

Использование GNU sedОбратите внимание, :первая строка abc не имеет mno согласно OP, поэтому мы можем использовать этот факт в приведенном ниже коде sed.

sed -e '
  /abc/,$!d
  /mno/{h;b;}
  $!{N;s/^/\n/;D;}
  x;/./d;x
' file

В этом методе мы используем режим slurp -zдля чтения всего файла в пространстве шаблонов. Затем мы удаляем до перед первой строкой, содержащей abc. После этого доберитесь до последней строки mno, используя жадность регулярного выражения.

sed -Ez '
  s/abc/\x0&/
  s/.*\n(.*)\x0/\1/
  s/(.*mno[^\n]*\n).*/\1/
' file

Еще один способ — двухпроходный -подход. где мы записываем номера строк первая строка abc и последняя строка mno.В Если нет, то мы вписываем $ вместо него. Затем, используя эти два числа, мы создать команду sed начало,конец p;конецq

sed -n '/abc/{=;:a;n;/mno/=;ba}' file |
sed -En '
  1{h;$s/.*/$/;}
  ${x;G;}
  s/\n(.*)/,\1p&q/p
' | sed -nf - file

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

perl -0777 -pe '
  s/^.*\n// until /^.*abc/;    /mno/||next;
  s/.*\n$// until /mno.*$/;
' file
1
16.09.2021, 00:15

Вот еще способы использования редактора sed чтобы получить желаемый результат.

sed -n '
  /\n/{/mno/!d;P;D;}
  /abc/,$H;$!d
  z;x;G;/mno/D
  s/.//;s/.$//p
' file
  • Сохраните файл с первого /abc/ до конца в области хранения.
  • напечатать верхнюю часть пространства шаблона, пока мы все еще можем видеть /mno/ в любом месте.
  • Затем обрежьте верхнюю часть пространства шаблона и повторите предыдущий шаг.
  • Остановиться, когда /mno/ перестанет отображаться.
  • В качестве альтернативы, перед началом этого цикла P;D, если нет /mno/, то просто напечатать все пространство хранения.

Еще один метод, при котором мы сохраняем строки в режиме ожидания только до тех пор, пока не будет виден /mno/. В этот момент мы переворачиваем и печатаем то, что было в ожидании.

sed -n '
  /abc/,$!d
  /mno/!{H;ba;}
  x;p;:a
  ${x;//P;//!p}
' file | sed 1d

Вот способ Python, использующий универсальный метод groupby модуля itertools для выполнения работы.

python3 -c 'import sys, itertools as it
ifile,start,stop = sys.argv[1:]
G,K,F = [],[],lambda x: x.find(stop)
with open(ifile) as f:
  for _ in f:
    if not _.find(start): continue
    for t in it.groupby(f,F):
      G.append(list(t[1]))
      K += [t[0] > -1]
if len(K) > 1 and not K[-1]: G.pop()
print(*[e for L in G for e in L], sep="",end="")
' file "abc" "mno"
1
17.09.2021, 13:53

Теги

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