find: 'count=1': Arquivo ou diretório inexistente

find: 'count=1': Arquivo ou diretório inexistente

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, findtentarei executar o argumento -execcomo 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 findinicia 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 findto 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 rootfscontiver subdiretórios. Você deve lidar com este caso ou usar findas opções -maxdepthpara -type fevitar esse problema.

Responder2

Parece que você está tentando executar todo e qualquer comando com -exec. Isso não funcionaria no caso geral, pois -execapenas executa comandos externos.

Em vez disso, chame um único script in-line e deixe-o findatuar 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 rootfsdiretório. Para lotes desses arquivos, um pequeno sh -cscript 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 -lconta 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, bashpor 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 globstaropção shell estiver definida. Também configurei dotglobpara poder ver nomes ocultos e a nullglobopçã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"

informação relacionada