Как назвать файл на самом глубоком уровне дерева каталогов

Для Вашего надлежащего использования древний, но пригодный к эксплуатации RCS или системы CVS могут уже существовать и на AIX и на Red Hat, и совершенно приемлемы для отдельного пользователя. Их легко изучить, быстро, не тяжелы на ресурсах и очень, очень хорошо отлажены код. IDE и клиенты GUI имеются в большом количестве для CVS. Можно скомпилировать обе системы сами и поместить исполняемые файлы примерно где угодно (как $HOME/bin).

CVS позволяет Вам помещать "репозиторий" в произвольный каталог, который мог бы добраться, Вы копируете (репозитория) бесплатно, устраняя это headeache.

С RCS Вы или получили ужасные каталоги RCS/везде, или можно использовать символьные ссылки на "репозиторий".

Иногда старая школа является лучшей школой.

4
17.12.2011, 21:35
7 ответов

Это - нечетный запрос!

Я использовал бы find + awk захватить файл в самом глубоком каталоге:

bash-3.2$ deepest=$(find / -type f | awk -F'/' 'NF > depth {
>     depth = NF;
>     deepest = $0;
> }
>
> END {
>     print deepest;
> }')

Используя ${deepest} в Вашем mv команду оставляют как осуществление, но следующие пять строк могут помочь Вам далее:

bash-3.2$ echo "${deepest}"
/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/Buenos_Aires.rb

bash-3.2$ echo "${deepest%.*}"
/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/Buenos_Aires

bash-3.2$ echo "${deepest%/*}"
/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina

bash-3.2$ echo "${deepest##*/}"
Buenos_Aires.rb

bash-3.2$ echo "${deepest##*.}"
rb

Следующее обновление вопроса:

find -type d [...] "Это только нашло бы каталог. [...], Как это могло быть решено самым простым способом?".

Путем предоставления -type f кому: find найти все файлы (f), не все каталоги (d).

10
27.01.2020, 20:45
  • 1
    я обновил свой вопрос и добавил сценарий командной строки, который я записал, чтобы попытаться сделать это.Это не работает. Некоторая обратная связь от других будет одобрена. –  Robert Sundström 17.12.2011, 16:22
  • 2
    Ваша острота непостижима мне. Я сожалею, что не могу отладить это для Вас. Разве мой пример не делает то, что Вы попросили? –  Johnsyweb 18.12.2011, 05:14
  • 3
    Извините. Да, это делает. Я просто искал различные способы заняться проблемой, поскольку я довольно плохо знаком с Bash и парадигмой. Ваше решение делает это!! –  Robert Sundström 18.12.2011, 05:18
  • 4
    я вижу. Существует много способов решить это. Я рекомендую свое собственное решение, так как оно включает только один |, сведение к минимуму подпроцессов. –  Johnsyweb 18.12.2011, 06:24
  • 5
    N.B: Если Вы просто хотите распечатать имя файла, можно опустить deepest=$( [...] ) и запустите с find. Не действительно ясно, чего Вы пытаетесь достигнуть. –  Johnsyweb 18.12.2011, 06:31

Вы пропускаете некоторое курчавое заключение в скобки, Вы инвертировали сравнение, и необходимо распечатать результат:

find -type d | {
  declare COUNT=-1
  declare P=""
  while read LINE
    do echo $LINE
    declare C=$(echo $LINE | cut -c3- | sed "s/\//\n\//g" | grep '/' -c)
    echo $C
    if [ $C -gt $COUNT ]; then let COUNT=$C; let P=$LINE; echo "Done"; fi
  done
  echo deepest: "$P"
}

Немного улучшенная версия, с отладкой выброшенного материала:

find -type d -links 2 | (
  declare COUNT=-1
  P=""
  while IFS= read -r LINE; do
    declare C=$(echo $LINE | tr -cd / | wc -c)
    if [ $C -gt $COUNT ]; then let COUNT=$C; P=$LINE; fi
  done
  echo deepest: "$P"
)
4
27.01.2020, 20:45
  • 1
    @Stéphane, Вы могли указать оболочку, которую Вы использовали? Вопрос отмечен bash, но я предполагаю, что Вы использовали что-то еще, поскольку удар' дает это: “удар: локальный: может только использоваться в функции”. –  manatwork 18.12.2011, 14:34
  • 2
    @manatwork: Действительно я забыл тестировать снова с bash. Я использовал zsh и это было принято. Лучшее должно, возможно, использовать подоболочку, чтобы заниматься теми небольшими проблемами объема. –  Stéphane Gimenez 18.12.2011, 14:44
  • 3
    более быстрый способ получить значение C C=${LINE//[^\/]/}; C=${#C}. Кроме того, Вам не нужно declare ключевое слово, если Вы используете подоболочку для создания переменных локальными. –  Gilles 'SO- stop being evil' 19.12.2011, 01:39
  • 4
    Умный прием. О, и я думаю, что точка объявляет, должен был сделать те целочисленные переменные переменных, таким образом, я не сделал изменил его. –  Stéphane Gimenez 20.12.2011, 13:18
find -type f | awk -F/ 'NF > maxdepth { maxdepth = NF; file = $0 }; END {print file}'

И кажется, что это - по существу то же как этот ответ по другому вопросу, который Вы отправили, что случилось с этим?

3
27.01.2020, 20:45

Я пошел бы с ними, хотя они перестанут работать на именах файлов, содержащих ведущие пробелы. Первые выводы просто имя файла, второе включает путь к тому файлу также:

find -type f | sed 's:[^/]*/: :g' | LC_ALL=C sort | head -1 | sed 's/^ *//'

find -type f | sed 'h;s:[^/]*/: :g;G;s/\n/\t/' | LC_ALL=C sort | head -1 | sed 's/.*\t//'
1
27.01.2020, 20:45
function step () {
    d=$1
    d=$((d+1))
    res=$(find -mindepth $d -type d ! -empty)
    test -n "$res" && step $d || echo $((d-1))
}

find -mindepth $(step 0) -type d ! -empty | head -n 1 

Рекурсивно ступите глубже и глубже в каталоги, пока они содержат файл (! -empty). От последнего шага мы должны вычесть 1, и мы можем затем использовать результат через секунду find команда.

0
27.01.2020, 20:45

Следующий сценарий распечатывает самые длинные пути в файловой системе и/или ниже текущего каталога, но вместо использования find, это использует в своих интересах существующее locate база данных (потенциально очень длинных) путей без искать/пересекать (потенциально очень глубокие) структуры каталогов. Обратите внимание, что это считает каталоги для определения глубины, не только длины пути (но и это могло легко быть изменено/упрощено, чтобы сделать любого).

$ cat find-longest-path.sh
#!/bin/bash
pattern=$1
locate -r "^${PWD}/${pattern}" \
   | while read f; do printf "$(tr -cd / <<< "$f" | wc -c):$f\n"; done \
   | sort -nr -t: -k1 \
   | head -5

Это распечатывает самые глубокие 5 путей (head -5) из шаблона имени файла (regexp) начинающий с pwd. Вывод снабжается префиксом глубиной (т.е. количество /в пути). Для поиска просто определенного имени файла и/или шаблона, где угодно в файловой системе, удаляют $PWD и просто поиск locate -r /some_file$ (... и т.д., и т.д.).

Например,

$ ./find-longest-path.sh 'foo.*log$'
5:/path/to/deep/path/foo-12345.log
3:/path/to/shallow/foobar.log
0
27.01.2020, 20:45

С zsh:

f=(**/*(D.Oe:'REPLY=${REPLY//[^\/]}':[1])) && mv -- $f $f:h/new-name

Мы используем zsh рекурсивное подстановку ( ** / * ) и квалификаторы glob. (...) , с D для включения точечных файлов, . для выбора только обычных файлов и Oe: 'code' для определения порядка сортировки (здесь обратный из-за верхнего регистра O ) на основе значения $ ОТВЕТИТЬ после выполнения кода .

В этом коде текущий файл передается как $ REPLY . Мы удаляем все, кроме / символов в этом $ REPLY , и это то, что используется для порядка сортировки. Таким образом, файл с наибольшим количеством / сортируется последним, первый раз перевернутым, и мы выбираем этот первый с помощью [1].

bash с (недавним) эквивалентом инструментов GNU может выглядеть примерно так:

(
  export LC_ALL=C
  find . -type f -print0 |
    sed -z 'h;s:[^/]::g;G;s:[^/]::' |
    sort -rz |
    sed -z 's:/*::;q' |
    tr '\0' '\n'
)
1
27.01.2020, 20:45

Теги

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