Наличие списка путей, как я могу отфильтровать подкаталоги ранее упомянутых путей?

Скажем, у меня есть отсортированный список полных путей, как тот в моем ответе здесь (сокращенный и измененный для этого вопроса):

/proc
/proc/sys/fs/binfmt_misc
/proc/sys/fs/binfmt_misc
/run
/run/cgmanager/fs
/run/hugepages/kvm
/run/lock
/run/user/1000
/run/user/1000/gvfs
/tmp
/home/bytecommander/ramdisk

То, что я хочу, должно уменьшить этот список путем устранения всех путей, которые являются подкаталогами ранее упомянутых путей. Это означает для данного входа, я хочу этот вывод:

/proc
/run
/tmp
/home/bytecommander/ramdisk

Как это может быть сделано легко в использовании командной строки, например, Bash, sed, awk или какие-либо другие общие инструменты? Короткие решения, которые помещаются в одну строку, ценятся, но не требуются.

7
задан 13 April 2017 в 05:25

2 ответа

AWK

$ awk -F '/' 'oldstr && NR>1{ if($0!~oldstr"/"){print $0;oldstr=$0}};NR == 1{print $0;oldstr=$0}'  paths.txt 
/proc
/run
/tmp
/home/bytecommander/ramdisk
/var/zomg
/var/zomgkthx
/zomg
/zomgkthx

Путем это работает, достаточно просто, но порядок команд является значительным. Мы запускаем путем записи того, что первая строка и распечатывание его. Мы переходим к следующей строке и проверке, если следующая строка содержит предыдущий текст. Если это делает - мы ничего не делаем. Если это не делает - это - другой, новый путь.

Исходный подход был испорчен и перестал работать, когда были смежные пути с той же ведущей подстрокой, такой как /var/zomg и /var/zomgkthx (Благодаря Chai T.Rex для указания на это). Прием должен добавить "/" к старому пути для выражения окончания его, таким образом повредив подстроку. Тот же подход используется в альтернативе Python ниже.

Альтернатива Python

#!/usr/bin/env python
import sys,os

oldline = None
with open(sys.argv[1]) as f:
     for index,line in enumerate(f):
         path = line.strip()
         if index == 0 or not line.startswith(oldline):
             print(path)
             oldline = os.path.join(path,'')

Образец выполняется:

$ ./reduce_paths.py paths.txt                                                                                     
/proc
/run
/tmp
/home/bytecommander/ramdisk
/var/zomg
/var/zomgkthx
/zomg
/zomgkthx

Этот подход является аналогичным awk один. Идея является тем же: запишите первую строку и продолжайте печатать и сбрасывать переменную отслеживания только, когда мы встречаемся со строкой, которая не имеет переменной отслеживания как стартовой подстроки.

С другой стороны, однажды мог использовать os.path.commonprefix() функция также.

#!/usr/bin/env python
import sys,os

oldline = None
with open(sys.argv[1]) as f:
     for index,line in enumerate(f):
         path = line.strip()
         if index == 0 or os.path.commonprefix([path,oldline]) != oldline:
             print(path)
             oldline = os.path.join(path,'')
10
ответ дан 23 November 2019 в 06:13

Другая версия Python, с помощью нового pathlib библиотека:

#! /usr/bin/env python3

import pathlib, sys

seen = set()
for l in sys.stdin:
    p = pathlib.Path(l.strip())
    if not any(x in seen for x in p.parents):
        seen.add(p)
        print(str(p))
8
ответ дан 23 November 2019 в 06:13

Другие вопросы по тегам:

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