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 -