Как вы взбираетесь на родительскую структуру каталогов bash-скрипта? - PullRequest
5 голосов
/ 27 августа 2010

Есть ли более аккуратный способ подняться на несколько уровней каталогов от места расположения скрипта.

Это то, что у меня сейчас есть.

# get the full path of the script
D=$(cd ${0%/*} && echo $PWD/${0##*/})

D=$(dirname $D)
D=$(dirname $D)
D=$(dirname $D)

# second level parent directory of script
echo $D

Я бы хотел аккуратный способнайти n-й уровень.Любые идеи, кроме как включить в цикл?

Ответы [ 7 ]

5 голосов
/ 27 августа 2010
dir="/path/to/somewhere/interesting"
saveIFS=$IFS
IFS='/'
parts=($dir)
IFS=$saveIFS
level=${parts[3]}
echo "$level"    # output: somewhere
2 голосов
/ 09 мая 2011
#!/bin/sh
ancestor() {
  local n=${1:-1}
  (for ((; n != 0; n--)); do cd $(dirname ${PWD}); done; pwd)
}

Использование:

 $ pwd
 /home/nix/a/b/c/d/e/f/g

 $ ancestor 3
 /home/nix/a/b/c/d
1 голос
/ 19 февраля 2016

Решением без циклов было бы использование рекурсии.Я хотел найти файл конфигурации для скрипта, возвращаясь назад из моего текущего рабочего каталога.

rtrav() { test -e $2/$1 && echo $2 || { test $2 != / && rtrav $1 `dirname $2`;}; }

Чтобы проверить, находится ли текущий каталог в репозитории GIT: rtrav .git $PWD

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

Предикат (test -e $2/$1) можно поменять местами для проверки счетчика, который указывает глубину обхода.

1 голос
/ 27 августа 2010

Какие-нибудь идеи, кроме включения цикла for?

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

И, кстати, самый простой способ сделать это в оболочке: echo $(cd $PWD/../.. && echo $PWD), где /../.. заставляет его раздеть два уровня.

С крошечным Perl это будет:

perl -e '$ENV{PWD} =~ m@^(.*)(/[^/]+){2}$@ && print $1,"\n"'

{2} в регулярном выражении Perl - это количество записей каталога для удаления. Или сделать его настраиваемым:

N=2
perl -e '$ENV{PWD} =~ m@^(.*)(/[^/]+){'$N'}$@ && print $1,"\n"'

Можно также использовать Perl split () , join () и splice () для этой цели, например ::

perl -e '@a=split("/", $ENV{PWD}); print join("/", splice(@a, 0, -2)),"\n"'

где -2 говорит, что из пути должны быть удалены последние две записи.

1 голос
/ 27 августа 2010

Если вы в порядке с включением команды Perl:

$ pwd
/u1/myuser/dir3/dir4/dir5/dir6/dir7

Первая команда выводит каталог, содержащий первые N (в моем случае 5) каталогов

$ perl-e 'use File::Spec; \
          my @dirs = File::Spec->splitdir( \
             File::Spec->rel2abs( File::Spec->curdir() ) ); \
          my @dirs2=@dirs[0..5]; print File::Spec->catdir(@dirs2) . "\n";'
/u1/myuser/dir3/dir4/dir5

Вторая команда выводит список каталогов N уровней вверх (в моем случае 5) каталогов (я думаю, вы хотели последний).

$ perl -e 'use File::Spec; \
           my @dirs = File::Spec->splitdir( \
              File::Spec->rel2abs( File::Spec->curdir() ) ); \
           my @dirs2=@dirs[0..$#dir-5]; print File::Spec->catdir(@dirs2)."\n";'
/u1/myuser

Чтобы использовать его в вашем bash-скрипте, конечно:

D=$(perl -e 'use File::Spec; \
           my @dirs = File::Spec->splitdir( \
              File::Spec->rel2abs( File::Spec->curdir() ) ); \
           my @dirs2=@dirs[0..$#dir-5]; print File::Spec->catdir(@dirs2)."\n";')
0 голосов
/ 24 июня 2011

Этот метод использует фактический полный путь к самому сценарию perl ... TIMTOWTDI Вы можете легко заменить $ RunDir на путь, с которого вы хотели бы начать ...

        #resolve the run dir where this scripts is placed
        $0 =~ m/^(.*)(\\|\/)(.*)\.([a-z]*)/; 
        $RunDir = $1 ; 
        #change the \'s to /'s if we are on Windows
        $RunDir =~s/\\/\//gi ; 
        my @DirParts = split ('/' , $RunDir) ; 
        for (my $count=0; $count < 4; $count++) {   pop @DirParts ;     }

        $confHolder->{'ProductBaseDir'} = $ProductBaseDir ; 
0 голосов
/ 10 мая 2011

Два уровня над каталогом скрипта:

echo "$(readlink -f -- "$(dirname -- "$0")/../..")"

Все кавычки и -- предназначены для избежания проблем с хитрыми путями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...