Em um script de shell, como dar uma variável a outro valor depois que um trabalho é feito?

0

Eu estou tentando fazer um script que vai ver se o diretório existe e vai zip todo o seu conteúdo sob ele de acordo com o nome / caminho do diretório.

O mais longe que eu pude ir foi -

#!/system/bin/sh -xv

Z="$PWD/../WorkingDir";
T='320';
F='480';
I='540';
D='dark';
L='light';
P='play';

cd $Z;

if [ -d $T/$D ]; then
    R=""$T"_"$D".zip";
else
    if [ -d $T/$L ]; then
        R=""$T"_"$L".zip";
    else
        R="file.zip";
    fi
fi;

for dir in */*/; do
    #Skip directories where the zip already exists
    [ -e "$dir"/"$R" ] || 
    ( cd -- "$dir" && zip -0rq "$R" .)
done

Mas isso acontece -

#!/system/bin/sh -xv
...
.
.
if [ -d $T/$D ]; then
    R=""$T"_"$D".zip";
else
    if [ -d $T/$L ]; then
        R=""$T"_"$L".zip";
    else
        R="file.zip";
    fi
fi;
+ [ -d 320/dark ]
+ R=320_dark.zip

for dir in */*/; do
    #Skip directories where the zip already exists
    [ -e "$dir"/"$R" ] ||
    ( cd -- "$dir" && zip -0rq "$R" .)
done
+ [ -e 320/dark//320_dark.zip ]
+ cd -- 320/dark/
+ zip -0rq 320_dark.zip .
+ [ -e 320/light//320_dark.zip ]
+ cd -- 320/light/
+ zip -0rq 320_dark.zip .
.
.
...and so on..

Cada arquivo recebe o mesmo nome ( 320_dark.zip neste caso). Eu quero diferente (de acordo com o nome da pasta / caminho) para cada arquivo que é compactado.

Eu queria -

+ [ -d 320/dark ]
+ R=320_dark.zip

- para alterar a cada vez para cada pasta. Como deveria ser 320_light.zip para o caminho da pasta 320/light .

A última parte da saída seria -

+ [ -e 320/dark//320_dark.zip ]
+ cd -- 320/dark/
+ zip -0rq 320_dark.zip .
+ [ -e 320/light//320_light.zip ]
+ cd -- 320/light/
+ zip -0rq 320_light.zip .
    
por Chinmay Kunkikar 07.02.2015 / 12:05

2 respostas

2

Aqui está minha sugestão, removendo variáveis de uma letra e mudando a localização do arquivo para fins de consistência:

#!/system/bin/sh -xv

cd "$PWD/../WorkingDir"

compress() {
    # Detect only known dir names, convert slash to underscore
    local arch="$(echo $1 | sed -rne '/320\/(light|dark)/s@/@_@gp')"

    # Set a default value to the variable
    : ${arch:=file}

    # Only create a ZIP archive if not present in the parent directory
    # Note $PWD is evaluated *before* cd
    [ -f "${arch}.zip" ] || ( cd -- $1 && zip -0rq "${PWD}/${arch}.zip ." )
}

for dir in */*/; do
    compress $dir
done

Basta alterar a linha sed para adicionar o que chamei de "nomes de diretório conhecidos".

EDITAR : Adicionando algumas explicações, conforme a solicitação do OP.

O script verifica as condições antes de compactar os diretórios sempre que um novo diretório é localizado pelo loop for . Variáveis também foram eliminadas. Vamos dissecar o código.

O loop principal

cd "$PWD/../WorkingDir"

for dir in */*/; do     # Ensures to select only directories
    compress $dir       # compress runs some checks prior to compressing
done

Na verdade, não há muito mais a dizer sobre isso.

A rotina compress

local arch="$(echo $1 | sed -rne '/320\/(light|dark)/s@/@_@gp')"

$1 é o argumento passado para compressed , ou seja, o diretório para verificar e compactar. O que sed faz primeiro ( '/320\/(light|dark)/' ) é verificar se o caminho está no formato

320/light
320/dark

e retorna o caminho com a barra convertida em um sublinhado: 's@/@_@g' . Usando o sinal de arroba como um separador para facilitar a leitura, para evitar escapar da barra. Outras notações válidas são 's:/:_:g' ou 's#/#_#g' ou o clássico 's/\//_/g' . Observe como a barra para transformar é escapada com um anti-slash. Eu acho a última forma menos legível embora.

O p à direita funciona em conjunto com sed -n ; a última opção neste caso em particular significa « não ecoa nada a menos que seja informado por p sempre que uma correspondência (ou seja, nas barras envolventes) for encontrada ». Portanto arch conterá um caminho com a barra transformada em um sublinhado se e somente se a expressão regular 320\/(light|dark) for encontrada no caminho. Caso contrário, não fará eco, tornando arch uma variável em branco.

A opção -r é uma maneira conveniente de informar sed para usar expressões regulares canônicas, mais legível. Caso contrário, você precisaria escapar dos parênteses e dos caracteres do pipe. Eu acho '/320\/(light|dark)/s@/@_@gp' mais legível que '/320\/\(light\|dark\)/s@/@_@gp' ou '/320\/\(light\|dark\)/s/\//_/gp' .

: ${arch:=file}

Esta linha define arch para seu valor padrão "file" se estiver em branco. A construção estranha é necessária porque ${arch:=file} sozinho dispara um erro de sintaxe. Os dois pontos dizem ao shell para não fazer nada ( : ), mas atribuem arch um valor, se estiver em branco.

    [ -f "${arch}.zip" ] || ( cd -- $1 && zip -0rq "${PWD}/${arch}.zip ." )

Aqui eu usei -f em vez de -e porque o primeiro também verifica arquivos com comprimento zero. O teste só terá sucesso se existir um arquivo ZIP e com comprimento diferente de zero.

Se não houver arquivo no diretório pai (ou no diretório atual ) ou se o tamanho for nulo, o script gerará um sub-shell que será alterado para o diretório passado como argumento para compress e fecha seu conteúdo. Note que as variáveis $1 e $PWD são avaliadas antes o sub-shell executa suas instruções, ou seja, $PWD é igual ao diretório pai $Z em sua versão inicial.

Expandindo o filtro

Você pode agir com base em sed da seguinte maneira:

sed -rne '/320\/(light|dark|play)/s@/@_@gp'

para verificar nomes de diretório como

320/light
320/dark
320/play

Você também pode considerar /(320|480|540)\/(light|dark|play)/ , o que lhe dá 9 combinações, ou um formulário mais genérico /[0-9]+\/(light|dark|play)/ (qualquer número seguido por uma barra e um de " luz ", " dark "e" play ") ou mesmo /[0-9]+\/\w+/ (qualquer número seguido por uma barra e uma palavra aka [A-Za-z0-9_]+ ). Tudo depende de quão rigoroso ou amplo você deseja que o filtro seja.

    
por 07.02.2015 / 14:20
1
#!/system/bin/sh -xv

Z=/absolute/path/to/WorkingDir
T=320
F=480 # ?
I=540 # ?
D=dark
L=light
P=play # ?

cd $Z

for dir in $Z*/*/; do

    if [ -d $Z/$T/$D ] && [ ! -f $T$D.zip ]; then
        zip -0rq $T$D.zip $dir;            
    elif [ -d $Z/$T/$L ] && [ ! -f $T$L.zip ]; then      # elif rules
        zip -0rq $T$L.zip $dir;
    # It's not very efficient to scale this up, but you could add more elif statements here.
    elif [ -d $Z/$F/$D ] && [ ! -f $F$D.zip]; then
        zip -0rq $F$D.zip $dir;
    # and so on..
    else
        exit
    fi;
done

Eu acho que isso é tudo que você precisa. Deixe-me saber se precisa de ajustes.

    
por 07.02.2015 / 14:10