Como eu atravesso de diretórios filhos para raiz?

3

Por exemplo, eu tenho um diretório

/path/to/directory

e quero definir as permissões de seus subdiretórios para algo. Isso é fácil:

find /path/to/directory -type d -exec chmod something {} +

Mas como faço isso ao contrário? Eu preciso definir a mesma permissão para

/path

e para

/path/to

e para

/path/to/directory

Eu tenho muitos diretórios como esse e estou procurando por alguma solução de script

    
por fdt 17.04.2017 / 15:01

3 respostas

1

Recarregue para cima até / ser alcançado e chame uma função para cada diretório.

#!/bin/sh

function mangleperms {
    echo DEBUG would chmod 755 "$1"
}

function walktoroot {
    DIR="$1"
    HANDLE="$2"
    if [ "$DIR" = "/" ]; then
        return
    fi
    "$HANDLE" "$DIR"

    # recursion (noun): see recursion
    PARENTDIR='dirname "$DIR"'
    walktoroot "$PARENTDIR" "$HANDLE"
}

if [ -z "$1" ]; then
    echo >&2 "Usage: walktoroot dir"
    exit 1
fi
# TODO probably more edge cases on relative dirs, though there are means
# to fully qualify those
if [ "$1" = "." ]; then
    DIR='pwd'
else
    DIR=$1
fi

walktoroot "$DIR" mangleperms

Por exemplo,

$ pwd
/var/tmp/a/b/c
$ /home/jdoe/walktoroot .
DEBUG would chmod 755 /var/tmp/a/b/c
DEBUG would chmod 755 /var/tmp/a/b
DEBUG would chmod 755 /var/tmp/a
DEBUG would chmod 755 /var/tmp
DEBUG would chmod 755 /var
$ 
    
por 17.04.2017 / 16:44
1

Com find , podemos fazer isso da seguinte maneira:

find /path/to/dir -type d -prune -exec chmod 755 {} \; -exec sh -c '
   while { set -- "${1%/*}"; case $1 in "" ) break ;; esac; }
   do find "$1" -type d -prune -exec chmod 755 \{\} \;; done
' {} {} \;

Outro método usando uma função recursive :

   fx() {
      case $1 in ?* ) chmod 755 "$1"; fx "${1%/*}" ;; esac
   }
   # and then...
   fx /path/to/dir
    
por 17.04.2017 / 23:30
0

Bem, um caminho é apenas uma string. Assim, você pode dividi-lo em / e aplicar seu comando a cada resultado. Por exemplo, você pode usar um pequeno perl one-liner para imprimir os caminhos pai:

$ path=/path/to/some/deeply/buried/thing
$ echo "$path" | perl -F"/" -lane 'for(1..$#F){print join("/",@F[0..$_])}'
/path
/path/to
/path/to/some
/path/to/some/deeply
/path/to/some/deeply/buried
/path/to/some/deeply/buried/thing

Se você agora criar uma função desse comando perl (execute este comando ou adicione-o ao arquivo de inicialização do seu shell - ~/.bashrc se você estiver usando bash ):

pexpand(){ 
   printf '%s\n' "$1" | perl -F"/" -lane 'for(1..$#F){print join("/",@F[0..$_])}'; 
}

Agora, você pode usá-lo assim:

$ pexpand $path
/path
/path/to
/path/to/some
/path/to/some/deeply
/path/to/some/deeply/buried
/path/to/some/deeply/buried/thing

E você pode executar comandos em cada diretório desse caminho com:

chmod 733 "$(pexpand "$path")"

A abordagem acima falhará se o seu caminho puder conter novas linhas. Uma versão mais robusta é:

pexpand(){ 
 perl -le '@F=split(/\//, $ARGV[0]); 
           for(1..$#F){printf "%s
pexpand "$path" | while IFS= read -r -d '' d; do chmod 733 "$d"; done
",join("/",@F[0..$_])}' "$1"; }

Isso é mais difícil de usar:

#!/usr/bin/perl

my $comm = $ARGV[0] || die "At least 2 arguments are necessary\n";
my $path = $ARGV[1] || die "At least 2 arguments are necessary\n";

my @paths=split(/\//, $path);
for (1..$#paths) {
    system("$comm \"" . join("/",@paths[0..$_]) . "\"");
}

Portanto, se você precisar disso para trabalhar com entradas arbitrárias, eu recomendo escrever um pequeno script que use o caminho e o comando como entrada:

foo.pl  "chmod 700" /path/to/some/deeply/buried/thing

Salve esse script como algo ( foo.pl ou qualquer outro) em um diretório no seu $PATH , torne-o executável ( chmod a+x ~/bin/foo.pl ) e agora você pode executá-lo assim:

$ path=/path/to/some/deeply/buried/thing
$ echo "$path" | perl -F"/" -lane 'for(1..$#F){print join("/",@F[0..$_])}'
/path
/path/to
/path/to/some
/path/to/some/deeply
/path/to/some/deeply/buried
/path/to/some/deeply/buried/thing
    
por 17.04.2017 / 17:54