найдите поиск в родительских каталогах вместо подкаталогов

Большинство нельдов не имеет понятия времени создания файла. Вы не можете сделать ls распечатайте его, потому что информация не зарегистрирована. При необходимости во времени создания используйте систему управления версиями: определите время создания как время регистрации.

Если Ваш вариант Unix имеет время создания, посмотрите на его документацию. Например, на   Mac OS X (единственный пример я знаю о ¹), использовать ls -tU. Windows также хранит время создания, но он не всегда выставляется портам утилит Unix, например, Cygwin ls не имеет опции показать его. stat утилита может показать время создания, названное “время рождения” в утилитах GNU, таким образом, под Cygwin можно показать файлы, отсортированные по рождению время с stat -c '%W %n' * | sort -k1n.

Обратите внимание что ctime (ls -lc) не время создания файла, это - время изменения inode. Время изменения inode обновляется каждый раз, когда что-либо об изменениях файла (содержание или метаданные) за исключением того, что ctime не обновляется, когда файл просто читается (даже если atime обновляется). В частности, ctime всегда более свеж, чем mtime (время изменения содержания файла), если mtime не был явно установлен на дату в будущем.

46
26.01.2011, 03:01
10 ответов

Еще более общая версия, которая позволяет использовать find опции:

#!/bin/bash
set -e
path="$1"
shift 1
while [[ $path != / ]];
do
    find "$path" -maxdepth 1 -mindepth 1 "$@"
    # Note: if you want to ignore symlinks, use "$(realpath -s "$path"/..)"
    path="$(readlink -f "$path"/..)"
done

Например (принимающий сценарий сохраняется как find_up.sh)

find_up.sh some_dir -iname "foo*bar" -execdir pwd \;

... распечатает названия всего из some_dirпредки (включая себя) до / в котором найден файл с шаблоном.

При использовании readlink -f вышеупомянутый сценарий будет следовать за символьными ссылками на пути, как отмечено в комментариях. Можно использовать realpath -s вместо этого, если Вы захотите продолжить, то пути по имени ("/foo/bar" подойдет к "нечто", даже если "панель" будет символьной ссылкой) - однако, который требует установки realpath который не установлен по умолчанию на большинстве платформ.

16
27.01.2020, 19:34
  • 1
    проблема с ними является способом, которым это разрешает ссылки. например, если я нахожусь в ~/foo/bar, и панель является символьной ссылкой на/some/other/place, затем ~ / нечто, и ~ / никогда не будет искаться. –  Erik Aronesty 05.06.2015, 16:07
  • 2
    @ErikAronesty, Вы правы - обновил ответ. Можно использовать realpath -s для получения поведения, Вы хотите. –  sinelaw 06.06.2015, 23:53
  • 3
    , который работает, когда Вы указываете полный путь для поиска. к сожалению, на песнях 5.8, realpath-s <dir> имеет ошибку, где, если <dir> относительно, то это разрешает символьные ссылки так или иначе... несмотря на, он - документация. –  Erik Aronesty 08.06.2015, 23:17
git rev-parse --show-toplevel

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

Другие связанные опции:

# `pwd` is inside a git-controlled repository
git rev-parse --is-inside-work-tree
# `pwd` is inside the .git directory
git rev-parse --is-inside-git-dir

# path to the .git directory (may be relative or absolute)
git rev-parse --git-dir

# inverses of each other:
# `pwd` relative to root of repository
git rev-parse --show-prefix
# root of repository relative to `pwd`
git rev-parse --show-cdup
29
27.01.2020, 19:34
  • 1
    Это работает только на мерзавца само. Вопрос более универсален. –  alex 26.01.2011, 09:15
  • 2
    Это не будет работать в пустом repo, –  Jason Pyeron 01.09.2014, 07:01

Обобщенная версия ответа Gilles, первый параметр раньше находил соответствие:

find-up () {
  path=$(pwd)
  while [[ "$path" != "" && ! -e "$path/$1" ]]; do
    path=${path%/*}
  done
  echo "$path"
}

Сохраняет использование символьных ссылок.

19
27.01.2020, 19:34

Находка не может сделать этого. Я не могу думать ни о чем более простом, чем цикл оболочки. (Непротестированный, предполагает, что существует нет /.git)

git_root=$(pwd -P 2>/dev/null || command pwd)
while [ ! -e "$git_root/.git" ]; do
  git_root=${git_root%/*}
  if [ "$git_root" = "" ]; then break; fi
done

Для конкретного случая репозитория мерзавца можно позволить мерзавцу сделать работу для Вас.

git_root=$(GIT_EDITOR=echo git config -e)
git_root=${git_root%/*}
15
27.01.2020, 19:34
  • 1
    Прохладный, это помещает меня на путь для общего решения - который я отправляю как другой ответ здесь. –  Vincent Scheib 07.10.2011, 03:56

При использовании zsh с расширенным включенным globbing можно сделать это с остротой:

(../)#.git(:h)   # relative path to containing directory, eg. '../../..', '.'
(../)#.git(:a)   # absolute path to actual file, eg. '/home/you/src/prj1/.git'
(../)#.git(:a:h) # absolute path to containing directory, eg. '/home/you/src/prj1'

Объяснение (заключенный в кавычки из man zshexpn):

Рекурсивный Globbing

Компонент пути формы (foo/)# соответствует пути, состоящему из нуля или большего количества каталогов, соответствующих нечто шаблона. Как стенография, **/ эквивалентно (*/)#.

Модификаторы

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

  • a
    • Превратите имя файла в полный путь: предварительно ожидает текущий каталог, при необходимости, и разрешает любое использование '..' и '.'
  • A
    • Как, но также и использование твердости символьных ссылок, если это возможно. Отметьте то разрешение '..' происходит перед разрешением символьных ссылок. Этот вызов эквивалентен, если Ваша система не имеет realpath системный вызов (современные системы делают).
  • h
    • Удалите запаздывающий компонент пути, оставив голову. Это работает как'dirname'.

Кредиты: Faux на #zsh для начального предложения использования (../)#.git(:h).

12
27.01.2020, 19:34
  • 1
    Это удивительно... Если я мог бы только выяснить (подсказка: необходимо сказать мне), что (../) делает... О, и кто/какой Faux on #zsh? –  alex gray 20.03.2015, 17:05
  • 2
    @alexgray (../) один не означает много, но (../)# средства пытаются развернуть шаблон в круглой скобке 0 или больше раз и только использовать тех, которые на самом деле существуют в файловой системе. Поскольку мы расширяемся от 0 до n родительских каталогов, мы эффективно ищем вверх на корень файловой системы (примечание: Вы, вероятно, хотите добавить что-то после того, как шаблон для создания этого значимым, но для просвещения выполнится print -l (../)#). И #zsh канал IRC, Faux имя пользователя на нем. Faux предложенный решение, поэтому кредит. –  unthought 22.03.2015, 13:03
  • 3
    Это развернет всех их. Можно хотеть: (../)#.git(/Y1:a:h) для остановки в первом найденном одного (с последней версией zsh), –  Stéphane Chazelas 08.06.2015, 23:43
  • 4
    Очень полезный, спасибо. Для включения расширенного globbing делают setopt extended_glob –  Shlomi 24.09.2015, 11:40

Эта версия findup поддерживает синтаксис «find», как в ответе @ sinelaw, но также поддерживает символические ссылки без необходимости использования реального пути. Он также поддерживает необязательную функцию «остановить в», так что это работает: findup.: ~ -Name foo ... ищет foo без передачи домашнего каталога.

#!/bin/bash

set -e

# get optional root dir
IFS=":" && arg=($1)
shift 1
path=${arg[0]}
root=${arg[1]}
[[ $root ]] || root=/
# resolve home dir
eval root=$root

# use "cd" to prevent symlinks from resolving
cd $path
while [[ "$cur" != "$root" && "$cur" != "/" ]];
do
    cur="$(pwd)"
    find  "$cur/"  -maxdepth 1 -mindepth 1 "$@"
    cd ..
done
0
27.01.2020, 19:34

Я обнаружил, что работа с символическими ссылками убивает некоторые другие параметры. Особенно конкретные ответы git. Я наполовину создал свой собственный фаворит из этого оригинального ответа, который довольно эффективен.

#!/usr/bin/env bash

# usage: upsearch .git

function upsearch () {
    origdir=${2-`pwd`}
    test / == "$PWD" && cd "$origdir" && return || \
    test -e "$1" && echo "$PWD" && cd "$origdir" && return || \
    cd .. && upsearch "$1" "$origdir"
}

Я использую символические ссылки для своих проектов go, потому что go требует, чтобы исходный код находился в определенном месте, и мне нравится хранить свои проекты в ~ / projects. Я создаю проект в $ GOPATH / src и привязываю его к ~ / projects. Таким образом, запуск git rev-parse --show-toplevel распечатывает каталог $ GOPATH, а не каталог ~ / projects. Это решение решает эту проблему.

Я понимаю, что это очень специфическая ситуация, но думаю, что решение ценное.

0
27.01.2020, 19:34

Я модифицировал решение sinelaw , чтобы оно соответствовало POSIX. Он не следует символическим ссылкам и включает поиск в корневом каталоге с использованием цикла do while.

find-up:
#!/usr/bin/env sh

set -e # exit on error
# Use cd and pwd to not follow symlinks.
# Unlike find, default to current directory if no arguments given.
directory="$(cd "${1:-.}"; pwd)"

shift 1 # shift off the first argument, so only options remain

while :; do
  # POSIX, but gets "Permission denied" on private directories.
  # Use || true to allow errors without exiting on error.
  find "$directory" -path "${directory%/}/*/*" -prune -o ! -path "$directory" "$@" -print || true

  # Equivalent, but -mindepth and -maxdepth aren't POSIX.
  # find "$directory" -mindepth 1 -maxdepth 1 "$@"

  if [ "$directory" = '/' ]; then
    break # End do while loop
  else
    directory=$(dirname "$directory")
  fi
done
0
27.01.2020, 19:34

Рекурсия может привести к весьма краткому решению.

#!/usr/bin/env bash

parent-find() {
  local file="$1"
  local dir="$2"

  test -e "$dir/$file" && echo "$dir" && return 0
  [ '/' = "$dir" ] && return 1

  parent-find "$file" "$(dirname "$dir")"
}

# Example
parent-find.bashrc "/home/user/projects/parent-find" 
# should respond with "/home/user"
1
17.03.2020, 23:23

Ответ

Так как есть вкладыш zsh one -, вот более общий вкладыш unix oneish -для поиска в 3 родительских каталогах:

$ name=fileOrDirName
$ eval find./$(printf "{$(echo %{1..4}q,)}" | sed 's/ /\.\.\//g')/ -maxdepth 1 -name $name

Пояснение

Я признаю, что это не самая красивая команда, но это одна строка. Для поиска 4 каталогов вверх замените echo %{1..4}q,на echo %{1..5}q,. Укажите имя файла или каталога с помощью переменной name.

Короче говоря, $(printf... | sed...)заменяется на его вывод с использованием подстановки команд , который затем расширяется с помощью findс использованием раскрытия фигурных скобок . В разбивке на две команды это выглядит так (с копией и вставкой посередине):

$ printf "{$(echo %{1..4}q,)}" | sed 's/ /\.\.\//g'
{'',../'',../../'',../../../'',}
$ #copy and paste the output

$ find./{'',../'',../../'',../../../'',} -maxdepth 1 -name $name

Вы можете узнать больше о расширениях оболочки в man bashили в ресурсах ниже на веб-сайте gnu

2
16.12.2020, 20:19

Теги

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