tar “Não é possível stat: Não existe tal arquivo de diretório” ao passar variáveis de array [closed]

1

Estou tentando escrever um script bash que criará um arquivo (tar) de arquivos em um diretório. As extensões de arquivo precisam ser passadas como argumentos ao chamar o script bash (./backup.bash pdf txt bak) assim. Estou usando a matriz para armazenar esses argumentos. O (ls | grep -i {array}) está procurando todos os arquivos no diretório que correspondem às extensões de arquivo inseridas no array e listará os arquivos encontrados. o (find. -type) está usando essas extensões para encontrar arquivos associados às extensões. O (tar cvf) está criando o arquivo de backup no diretório de trabalho com o nome backup.tar. Eu listei a matriz no final do comando tar, mas pensando nisso agora talvez eu pudesse canalizar o comando find para o comando tar.

my_array=([$@])
ls | grep -i \{my_array[$@]}
find . -type f \( -name "my_array[$@]" \)
tar cvf ./PATH/backup.tar my_array[$@]
    
por willDurango 02.10.2018 / 03:31

2 respostas

1

Existem dois problemas principais na resolução deste problema. Você precisa encontrar todos os arquivos com certos sufixos de nome de arquivo, dados por um usuário, e você precisa adicioná-los a um arquivo tar .

O comando find tem uma opção -name que você deseja usar corretamente, mas só pode usar um único padrão de nome de arquivo. Como o usuário do script está nos dando vários sufixos de nome de arquivo, teríamos que usar tantas opções de -name quantas forem sufixos.

Isso significa que temos que construir uma matriz de várias opções -name "PATTERN" , com -o entre elas (significando um "OR" lógico entre elas). Isso seria então usado com find para procurar nomes de arquivos com qualquer um dos sufixos de nomes de arquivos fornecidos.

O seguinte faz isso modificando a matriz $@ :

#!/bin/sh

for suffix do
    shift
    set -- "$@" -o -name "*.$suffix"
done
shift    # remove the very first "-o" from $@

find . -type f \( "$@" \)

Isso modifica a matriz $@ que, desde o início, já contém os sufixos dados na linha de comando. No loop, removemos o elemento frontal de $@ e inserimos nossas palavras no final da matriz.

Se chamar este script como

sh script.sh sh txt c

ele criaria um comando find que seria equivalente a

find . -type f \( -name '*.sh' -o -name '*.txt' -o -name '*.c' \)

Isso encontra todos os arquivos relevantes. Agora só temos que adicioná-los ao arquivo.

Com GNU tar (mas não com, por exemplo, BSD tar ), a ação r nos permite atualizar ou criar um arquivo (o BSD tar apenas atualiza mas não cria um novo arquivo).

backup=./PATH/backup.tar
rm -f "$backup"
find . -type f \( "$@" \) -exec tar -r -v -f "$backup" {} +

Isso criaria o arquivo ./PATH/backup.tar com os arquivos relevantes.

O motivo pelo qual eu não uso tar -c é que quando chamamos tar de find assim, tar pode ser chamado mais de uma vez. Se eu usasse tar -c para criar um novo arquivo, esse arquivo seria truncado sempre que tar fosse chamado (o que pode ser muitas vezes se find encontrar muitos milhares de arquivos). Usando tar -r , apenas continuamos atualizando o arquivo.

Assim, o script completo pode parecer algo assim:

#!/bin/sh

backup=./PATH/backup.tar

if [ "$#" -eq 0 ]; then
    echo 'No filename suffixes given' >&2
    exit 1
fi

for suffix do
    shift
    set -- "$@" -o -name "*.$suffix"
done
shift    # remove the very first "-o" from $@

rm -f "$backup"
find . -type f \( "$@" \) -exec tar -r -v -f "$backup" {} +

Observe que o uso de citações no script acima é bastante deliberado. Isso tornará possível arquivar arquivos com qualquer nome de arquivo permitido, incluindo nomes que contenham espaços, novas linhas e outros caracteres incomuns.

Relacionados:

Se estiver usando uma implementação find que tenha -print0 , você também pode passar os nomes dos caminhos encontrados para o GNU tar como no script abaixo:

#!/bin/sh

backup=./PATH/backup.tar

if [ "$#" -eq 0 ]; then
    echo 'No filename suffixes given' >&2
    exit 1
fi

for suffix do
    shift
    set -- "$@" -o -name "*.$suffix"
done
shift    # remove the very first "-o" from $@

find . -type f \( "$@" \) -print0 | tar -c -v -f "$backup" --null -T -

Com -print0 , find produzirá nomes de caminho delimitados por nul que o GNU tar lerá com suas opções --null -T - .

Esse último script como um script bash -específico (usando uma matriz, names para as opções -name ):

#!/bin/bash

backup=./PATH/backup.tar

if [ "$#" -eq 0 ]; then
    echo 'No filename suffixes given' >&2
    exit 1
fi

names=( -name "*.$1" )
shift
for suffix do
    names+=( -o -name "*.$suffix" )
done

find . -type f \( "${names[@]}" \) -print0 | tar -c -v -f "$backup" --null -T -
    
por 02.10.2018 / 08:26
0

Com zsh e GNU tar ou bsdtar :

#! /bin/zsh -
set -o extendedglob
output=file.tar.gz
printf '%s
#! /bin/zsh -
set -o extendedglob
output=file.tar.gz
printf '%s%pre%' **/*.(${(j:|:)~${(b)@}})~$output(D.) |
  tar --null -cf - -T - | xz > $output
' **/*.(${(j:|:)~${(b)@}})~$output(D.) | tar --null -cf - -T - | xz > $output
  • ${(b)@} : cita os parâmetros posicionais para evitar que sejam tomados como padrões
  • ${(j:|:)...} : une as palavras resultantes com |
  • ${~var} : trata a expansão como um padrão de globbing (agora parecendo jpg|gif|\* se os parâmetros posicionais forem jpg , gif , * )
  • **/ : qualquer nível de subdiretórios
  • pattern~$output : exclui o próprio arquivo de saída da expansão glob
  • Qualificadores (D.) : glob: inclua arquivos ocultos e selecione apenas arquivos regulares.
por 02.10.2018 / 08:52