Скажем, у меня есть отсортированный список полных путей, как тот в моем ответе здесь (сокращенный и измененный для этого вопроса):
/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
или какие-либо другие общие инструменты? Короткие решения, которые помещаются в одну строку, ценятся, но не требуются.
$ 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 ниже.
#!/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,'')
Другая версия 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))