Что можно использовать для получения путей ко всем родительским каталогам для заданного пути

Мне кажется, что у вас неправильное имя репозитория. Я не вижу google-cloud-monitoring-bionic.

Возможно ли это google-cloud-monitoring-xenial?

Просмотрите https://packages.cloud.google.com/apt/distsв веб-браузере, чтобы просмотреть доступные репозитории.

1
01.08.2020, 12:09
5 ответов

Если вы согласны с созданием нового каталога в папке /tmp, вы можете использовать команду find, этот метод также позаботится о печати только уникальных имен каталогов.

#!/bin/bash
if [[ $# -eq 0 ]]; then exit; fi
mkdir -p /tmp/printnames
for i
do
  mkdir -p /tmp/printnames/"$i"
done
cd /tmp/printnames
find *  -type d -print
rm -r /tmp/printnames

Таким образом, вы можете создать временную структуру каталогов, а затем перемещаться по ней с помощью find.

1
18.03.2021, 23:15

Сценарий Python, использующий стандартный модуль pathlib, работающий с аргументами вместо ввода:

#! /usr/bin/env python3

import sys

from collections import OrderedDict
from pathlib import Path

paths = OrderedDict()  # to maintain ordering and skip duplicates

for arg in sys.argv[1:]:
    path = Path(arg)
    for subpath in reversed(path.parents):
        # add the parents
        paths[subpath.as_posix()] = subpath
    # add the path itself
    paths[path.as_posix()] = path

# we don't need '.' in the output
if '.' in paths:
    paths.pop('.')

print('\n'.join(paths.keys()))

(Можно было бы легко модифицировать его для использования stdin, зациклив вместо этого sys.stdin.)

Пример:

%./foo.py dir1/file1 dir1/file2 foo/bar/moocow
dir1
dir1/file1
dir1/file2
foo
foo/bar
foo/bar/moocow
2
18.03.2021, 23:15

Этот код сделает это. Он не использует временные файлы. Он работает с пробелами, однако новые строки неоднозначны (измените \nна \0, чтобы исправить ). Вы должны использовать \0, если он будет использоваться в автоматизированных процессах. \0— единственный символ, который гарантированно не встречается в имени файла Unix.

Он просто рекурсивно использует dirnames. Вы можете настроить его, удалив/включив некоторые из printfs. Чтобы сделать его восходящим или нисходящим, или чтобы не отображать корневой узел(.или/). В вашем примере не было показа корневого узла, но я думаю, что он нужен. Без него /a/b/cдает тот же результат, что и a/b/c.

#!/bin/bash

function dirnames {
    local input
    local parent
    input="$1"
    if [[ "$input" == "" ]]
    then
        true
    elif [[ "$input" == "." ||  "$input" == "/" ]]
    then
        printf '%s\n' "$input" #print the root node
    else
        #printf '%s\n' "$input"  #print node (descending)
        parent="$(dirname "$input")"
        dirnames "$parent"
        printf '%s\n' "$input" #print node (ascending)
    fi
}

for d in "$@"
do
    dirnames "$d"
done

Пример использования

%↳./dirnames a/b/c
.
a
a/b
a/b/c
%↳./dirnames /a/b/c
/
/a
/a/b
/a/b/c
%↳

Чтобы заставить его работать вот так

%↳./dirnames a/b/c
.
a
b
c
%↳./dirnames /a/b/c
/
a
b
c
%↳

, затем сохраните файл как dirnames, затем запустите sed -r -i '17 s/("[$]input")/"$(basename \1)"/' dirnames. Теперь у вас будет скрипт, который выводит только листья на каждом уровне.

1
18.03.2021, 23:15

Учитывая, что вы собираетесь обрабатывать пути как текст, с неявными предположениями, что они не будут содержать символы новой строки и что их не нужно канонизировать, вы можете направить их в этот скрипт:

#!/bin/awk -f
BEGIN {
  FS="/"
}
{
  f = ""
  for (i=1; i<=NF; i++) {
    f = f (i>1 ? FS : "") $i
    if (! p[f]++ && f)
      print f
  }
}

Каждая строка ввода разбивается на /. Затем поля объединяются с первого по последнее, разделенные символом /, и каждый промежуточный результат(fфрагмента )сохраняется как значение индекса ассоциативного массива(paths ). Печатается каждый не-пустой 1 фрагмент, который еще не встречался.

Обратите внимание, что foo, /foo, foo/, /foo/и даже /foo//будут считаться отдельными путями, и все они будут распечатаны отдельно.

1Первый в абсолютных путях, которые в AWK имеют пустое поле перед первым/

1
18.03.2021, 23:15

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

$ sed -nE 's%/+(/[^/]|$)%\1%g;:loop;\%(^[^/]+|/[^/]*)$%{p;s///};tloop' | LC_ALL=C sort -u

Приведенный выше сценарий Sed доходит до степени объединения смежных /символов (самая первая sкоманда до первой ;делает это ), но кроме этого он не знает относительного дорожки и т. д.

Обратите внимание, что сценарий совместим с POSIX, хотя в некоторых системах вам может потребоваться ввести его в несколько строк, например, так:

$ sed -nE 's%/+(/[^/]|$)%\1%g
:loop
\%(^[^/]+|/[^/]*)$%{
p;s///
}
tloop
' | LC_ALL=C sort -u

Также обратите внимание, что он не может обрабатывать новые строки в именах файлов. Однако в расширенных инструментах, поддерживающих параметр -z, вы можете просто добавить его как к sed, так и к sort, чтобы получить ввод-вывод с нулевым -разделителем.

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

Я использовал Awk из-за его полезных встроенных механизмов для разделения и перестроения строк.

#!/usr/bin/awk -f

BEGIN { FS="/+"; OFS="/" }
{
    for (nfields=dotdot=0; NF; NF--) {
        if (path[nfields]=$NF) {
            if ($NF=="..") dotdot++
            else if ($NF!=".") {
                if (dotdot) dotdot--
                else nfields++
            }
        }
    }
    if (nfields in path && !path[nfields])
        $1=""
    else {
        while (dotdot--) path[nfields++]=".."
        path[nfields++]="."
    }
    while (nfields--) {
        $(NF+1) = path[nfields]
        if (!seen[$0]++) print $0
    }
}

Вы можете обрабатывать новые строки в именах файлов, вызывая их с помощью -v RS='\0' -v ORS='\0'в реализациях Awk (, таких как GNU Awk ), которые поддерживают nul RS.

ХТХ

0
18.03.2021, 23:15

Теги

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