2010-08-27 15 views
5

Czy istnieje lepszy sposób na wspinanie się po wielu poziomach katalogów z lokalizacji skryptu.Jak wspiąć się na strukturę katalogu nadrzędnego skryptu bash?

To właśnie mam obecnie.

# 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 

Chciałbym schludny sposób na znalezienie n-tego poziomu. Jakieś pomysły poza wprowadzaniem pętli for?

Odpowiedz

5
dir="/path/to/somewhere/interesting" 
saveIFS=$IFS 
IFS='/' 
parts=($dir) 
IFS=$saveIFS 
level=${parts[3]} 
echo "$level" # output: somewhere 
1

Jeśli jesteś OK z tym poleceniu Perl:

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

Pierwsze polecenie wymienia katalog zawierający pierwsze N ​​(w moim przypadku 5) spisy

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

Drugi list polecenie katalog N poziomów w górę (w moim przypadku 5) katalogów (myślę, że chciałeś tego ostatniego).

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

Aby użyć go w skrypcie bash, oczywiście:

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

Dziękuję za odpowiedź. Nie znam perla. Wszelkie alternatywy przy użyciu awk, sed byłyby bardzo docenione. – Michael

+0

@Michael - nie, nie możesz tego zrobić w awk lub sed - logika jest zawarta w bibliotece Perl 'File :: Spec' i składni wycinka tablicy (' @ dirs2 = @ dirs [0 .. $ # dir- 5] '). Jednak nie musisz ** znać ** perla, aby użyć tej odpowiedzi - po prostu skopiuj/wklej ostatnią linię do skryptu powłoki tak jak jest (po przetestowaniu oczywiście) i zmień "5" na żądaną głębokość. – DVK

1

Wszelkie pomysły inne niż oddanie w pętli for?

W powłokach nie można ominąć pętli, ponieważ tradycyjnie nie obsługują wyrażenia regularnego, ale dopasowują glob. Wzorce globalne nie obsługują żadnych powtórzeń liczników.

I BTW, najprostszy sposób to zrobić w powłoce: echo $(cd $PWD/../.. && echo $PWD), gdzie /../.. sprawia, że ​​pasek dwa poziomy.

Z odrobiną Perl że byłoby:

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

{2} w wyrażeniu regularnym Perl jest liczba wpisów katalogowych rozebrać. Lub co konfigurowalne:

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

Można również użyć Perl split(), join() i splice() do tego celu, np:

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

gdzie -2 mówi, że z drogi dwa ostatnie wpisy ma być usunięty .

2
#!/bin/sh 
ancestor() { 
    local n=${1:-1} 
    (for ((; n != 0; n--)); do cd $(dirname ${PWD}); done; pwd) 
} 

Zastosowanie:

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

$ ancestor 3 
/home/nix/a/b/c/d 
0

Dwa poziomy powyżej katalogu skryptu:

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

Wszystkie cytowania i -- to uniknąć problemów z trudnych ścieżkach.

0

Ta metoda używa rzeczywistej pełnej ścieżki do samego skryptu perl ...TIMTOWTDI Można łatwo wymienić tylko $ RunDir ze ścieżką chcesz zacząć ...

 #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 ; 
1

rozwiązanie bez pętle byłoby użyć rekursji. Chciałem znaleźć plik konfiguracyjny skryptu, przechodząc wstecz z mojego bieżącego katalogu roboczego.

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

Aby sprawdzić, czy bieżący katalog jest w repo GIT: rtrav .git $PWD

rtrav sprawdzi istnienie pliku podanego przez pierwszy argument w każdej folderu nadrzędnego w jednym określonym jako drugi argument. Drukowanie ścieżki katalogu, w którym plik został znaleziony lub zamknięty z kodem błędu, jeśli plik nie został znaleziony.

Predykat (test -e $2/$1) można zamienić na sprawdzenie licznika wskazującego głębokość przejścia.

+0

Piękny. Dodano do mojego '.bashrc'. –

Powiązane problemy