Código anterior:
total=`ls -Rp rootfs | wc -l`
count=0
Quando atribuo uma adição simples a uma variável:
sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=$((count+1)) \; -exec echo -en "\rcopiati: $count/$total" \;
Eu recebo:
find: ‘count=1’: No such file or directory
Além disso, quando eu exec:
sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=1 \; -exec echo -en "\rcopiati: $count/$total" \;
Eu recebo o mesmo erro. Por que?
Para cada arquivo copiado quero o contador: 1/13444, que é atualizado para 2/13444, 3/13444, etc...
editar:
Encontrei um método, mas ele não vê arquivos ocultos. Como posso fazer com que eles os vejam em um loop for?
#!/bin/bash
copysync() {
countfiles() {
for f in $1/*; do
if [ -d "$f" ]; then
countfiles "$f"
else
if [ "${f: -2}" != "/*" ]; then
total=$((total+1))
fi
fi
done
}
recursivecp() {
for f in $1/*; do
if [ -d "$f" ]; then
mkdir -p "/media/$USER/$f"
recursivecp "$f"
else
if [ "${f: -2}" != "/*" ]; then
sudo cp -a "$f" "/media/$USER/$f"
sudo sync
count=$((count+1))
echo -en "\rCopied: $((count*100/total))%"
fi
fi
done
}
total=0
countfiles $1
count=0
recursivecp $1
}
copysync rootfs
Responder1
O shell se expande count=$((count+1))
antes de ser executado find
.
Em seguida, find
tentarei executar o argumento -exec
como um comando. Este deve ser um programa ou script, não pode ser um shell embutido ou uma sintaxe de shell para atribuição de variáveis.
Contar os arquivos encontrados não funciona desta forma porque find
inicia um novo processo para -exec
, portanto o resultado de uma atribuição de variável não estaria disponível no shell pai.
Sugiro imprimir uma linha para cada arquivo encontrado e canalizar a saída de find
to wc -l
, por exemplo
find rootfs -exec cp -d -- "{}" "/media/$USER/{}" \; -exec sync \; -print|wc -l
Para obter alguma saída ao copiar os arquivos, você pode usar algo assim:
find rootfs|while IFS= read -r file
do
cp -d -- "$file" "/media/$USER/$file"
sync
count=$((count+1))
echo -en "\rcopiati: $count/$total"
done
Observações:
Isso não funciona para nomes de arquivos que contenham uma nova linha (e talvez outros caracteres especiais).
O script pode não funcionar se rootfs
contiver subdiretórios. Você deve lidar com este caso ou usar find
as opções -maxdepth
para -type f
evitar esse problema.
Responder2
Parece que você está tentando executar todo e qualquer comando com -exec
. Isso não funcionaria no caso geral, pois -exec
apenas executa comandos externos.
Em vez disso, chame um único script in-line e deixe-o find
atuar como gerador de um loop nesse script:
find rootfs -type f -exec sh -c '
for pathname do
cp -d "$pathname" "/media/$USER" &&
echo . &&
sync
done' sh {} + | wc -l
Isso encontraria todos os arquivos regulares dentro ou abaixo do rootfs
diretório. Para lotes desses arquivos, um pequeno sh -c
script embutido é chamado. Este script copia cada arquivo para um determinado diretório, gera um ponto seguido por uma nova linha para cada arquivo copiado com sucesso e chama sync
.
O wc -l
conta o número de pontos gerados e relata essa contagem. Não contamos os nomes de caminho em si, pois esta contagem seria enganosa se qualquer nome de caminho contivesse um caractere de nova linha incorporado.
Sem usar find
, isso pode ser feito, bash
por exemplo:
shopt -s globstar dotglob nullglob
for pathname in rootfs/**/*; do
[[ ! -f $pathname ]] && continue
cp -d "$pathname" "/media/$USER" &&
echo . &&
sync
done | wc -l
Isso usa um padrão globbing contendo o **
glob que corresponde aos subdiretórios inte se a globstar
opção shell estiver definida. Também configurei dotglob
para poder ver nomes ocultos e a nullglob
opção de shell para evitar a execução do loop se o padrão não corresponder a nada.
A mesma coisa, mas com um contador:
shopt -s globstar dotglob nullglob
count=0
for pathname in rootfs/**/*; do
[[ ! -f $pathname ]] && continue
cp -d "$pathname" "/media/$USER" &&
count=$(( count + 1 ))
sync
done
printf 'count=%d\n' "$count"