buscar: 'count=1': No existe tal archivo o directorio

buscar: 'count=1': No existe tal archivo o directorio

Código anterior:

total=`ls -Rp rootfs | wc -l`
count=0

Cuando asigno una simple suma a una variable:

sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=$((count+1)) \; -exec echo -en "\rcopiati: $count/$total" \;

Yo obtengo:

find: ‘count=1’: No such file or directory

También cuando ejecuto:

sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=1 \; -exec echo -en "\rcopiati: $count/$total" \;

Me sale el mismo error. ¿Por qué?

Para cada archivo copiado quiero el contador: 1/13444, que se actualiza a 2/13444, 3/13444, etc.

editar:

Encontré un método pero no ve archivos ocultos, ¿cómo puedo hacer que los vean en un bucle 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

Respuesta1

El shell se expande count=$((count+1))antes de ejecutarse find.

Luego findintentará ejecutar el argumento -execcomo un comando. Debe ser un programa o script, no puede ser un shell incorporado o una sintaxis de shell para la asignación de variables.

Contar los archivos encontrados no funciona de esta manera porque findinicia un nuevo proceso para -exec, por lo que el resultado de una asignación de variable no estaría disponible en el shell principal.

Sugiero imprimir una línea para cada archivo encontrado y canalizar la salida finda wc -l, por ejemplo

find rootfs -exec cp -d -- "{}" "/media/$USER/{}" \; -exec sync \; -print|wc -l

Para obtener algunos resultados al copiar los archivos, puede usar algo como esto:

find rootfs|while IFS= read -r file
do
    cp -d -- "$file" "/media/$USER/$file"
    sync
    count=$((count+1))
    echo -en "\rcopiati: $count/$total"
done

Observaciones:

Esto no funciona para nombres de archivos que contienen una nueva línea (y tal vez otros caracteres especiales).

Es posible que el script no funcione si rootfscontiene subdirectorios. Debe manejar este caso o usar findlas opciones de -maxdepthy -type fevitar este problema.

Respuesta2

Parece como si estuvieras intentando ejecutar todos y cada uno de los comandos con -exec. Esto no funcionaría en el caso general ya que -execsólo ejecuta comandos externos.

En su lugar, llame a un único script en línea y déjelo findactuar como generador de un bucle en ese script:

find rootfs -type f -exec sh -c '
    for pathname do
        cp -d "$pathname" "/media/$USER" &&
        echo . &&
        sync
    done' sh {} + | wc -l

Esto encontraría todos los archivos normales dentro o debajo del rootfsdirectorio. Para lotes de estos archivos, sh -cse llama a un breve script en línea. Este script copia cada archivo en el directorio indicado, genera un punto seguido de una nueva línea para cada archivo copiado correctamente y llama sync.

Cuenta wc -lel número de puntos generados e informa este recuento. No contamos los nombres de ruta en sí, ya que este recuento sería engañoso si algún nombre de ruta contiene un carácter de nueva línea incrustado.

Sin usar find, esto se puede hacer, por ejemplo bash, así:

shopt -s globstar dotglob nullglob

for pathname in rootfs/**/*; do
    [[ ! -f $pathname ]] && continue
    cp -d "$pathname" "/media/$USER" &&
    echo . &&
    sync
done | wc -l

Esto utiliza un patrón global que contiene el **global que coincide con los subdirectorios internos si la globstaropción Shell está configurada. También configuré dotglobpoder ver nombres ocultos y la nullglobopción de shell para evitar ejecutar el bucle si el patrón no coincide con nada.

Lo mismo, pero con 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"

información relacionada