2010-08-27 12 views
5

¿Hay alguna manera más clara de subir varios niveles de directorios desde la ubicación de un script?¿Cómo se sube a la estructura del directorio padre de un script bash?

Esto es lo que tengo actualmente.

# 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 

Me gustaría una forma ordenada de encontrar el enésimo nivel. ¿Alguna otra idea que no sea poner en un bucle for?

Respuesta

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

Si estás bien con la inclusión de un comando de Perl:

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

El primer comando enumera el directorio que contiene la primera N (en mi caso) 5 directorios

$ 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 

El segundo comando muestra la el directorio N nivela los directorios (en mi caso 5) (creo que usted quería el último).

$ 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 

Para utilizarlo en su escritura del golpe, por supuesto:

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

Gracias por su respuesta. No estoy familiarizado con Perl. Cualquier alternativa que use awk, sed sería muy apreciada. – Michael

+0

@Michael - no, no se puede hacer eso en awk o sed - la lógica se encapsula en la biblioteca 'File :: Spec' de Perl y en la sintaxis del segmento de matriz (' @ dirs2 = @ dirs [0 .. $ # dir- 5] '). Sin embargo, no necesita ** saber ** perl para usar esta respuesta: simplemente copie/pegue la última línea en su script de shell tal como está (después de probarlo por supuesto) y cambie "5" a la profundidad deseada. – DVK

1

Cualquier idea que no sea puesta en un bucle?

En shells, no se puede evitar el bucle, ya que tradicionalmente no admiten la expresión regular, pero sí el emparejamiento global. Y los patrones glob no son compatibles con ningún tipo de contadores de repetición.

Y, por cierto, la forma más sencilla es hacerlo en shell es: echo $(cd $PWD/../.. && echo $PWD) donde el /../.. hace que se desnivele dos niveles.

Con poco de Perl que sería:

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

El {2} en la expresión regular del Perl es el número de entradas de directorio para despojar. O lo que es configurable:

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

También se puede utilizar de split(), join() y splice() con el propósito, Perl, por ejemplo:

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

donde -2 dice que a partir de la trayectoria de las dos últimas entradas tiene que ser eliminado .

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

Uso:

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

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

dos niveles por encima del script del directorio:

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

Toda la cotización y -- son para evitar problemas con caminos difíciles.

0

Este método usa la ruta completa real al script perl en sí ...TIMTOWTDI Se podía reemplazar fácilmente los $ RunDir con el camino que le gustaría comenzar con ...

 #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

Una solución sin bucles sería utilizar la recursividad. Quería encontrar un archivo de configuración para una secuencia de comandos atravesando hacia atrás desde mi actual directorio de trabajo.

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

Para comprobar si el directorio actual se encuentra en un repositorio git: rtrav .git $PWD

rtrav comprobará la existencia de un nombre de archivo dado por el primer argumento en cada carpeta principal de la que se da como el segundo argumento. Imprimir la ruta del directorio donde se encontró el archivo o salir con un código de error si no se encontró el archivo.

El predicado (test -e $2/$1) podría intercambiarse para verificar un contador que indique la profundidad del cruce.

+0

Hermoso. Agregado a mi '.bashrc'. –

Cuestiones relacionadas