find: 'count=1': Keine solche Datei oder kein solches Verzeichnis

find: 'count=1': Keine solche Datei oder kein solches Verzeichnis

Vorheriger Code:

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

Wenn ich einer Variablen eine einfache Addition zuweise:

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

Ich bekomme:

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

Auch wenn ich ausführe:

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

Ich erhalte den gleichen Fehler. Warum?

Für jede kopierte Datei möchte ich den Zähler: 1/13444, der auf 2/13444, 3/13444 usw. aktualisiert wird …

bearbeiten:

Ich habe eine Methode gefunden, aber sie sieht keine versteckten Dateien. Wie kann ich dafür sorgen, dass sie in einer For-Schleife angezeigt werden?

#!/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

Antwort1

Die Shell wird count=$((count+1))vor der Ausführung erweitert find.

Anschließend findwird versucht, das Argument als Befehl auszuführen -exec. Dies muss ein Programm oder Skript sein, es kann kein Shell-Builtin oder Shell-Syntax für die Variablenzuweisung sein.

Das Zählen der gefundenen Dateien funktioniert auf diese Weise nicht, da findfür einen neuen Prozess ein neuer Prozess gestartet wird -execund das Ergebnis einer Variablenzuweisung daher in der übergeordneten Shell nicht verfügbar wäre.

Ich schlage vor, für jede gefundene Datei eine Zeile auszudrucken und die Ausgabe beispielsweise findan weiterzuleiten.wc -l

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

Um beim Kopieren der Dateien eine Ausgabe zu erhalten, können Sie etwa Folgendes verwenden:

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

Bemerkungen:

Dies funktioniert nicht für Dateinamen, die eine neue Zeile (und möglicherweise andere Sonderzeichen) enthalten.

Das Skript funktioniert möglicherweise nicht, wenn rootfsUnterverzeichnisse enthalten sind. Sie sollten diesen Fall entweder selbst behandeln oder finddie Optionen -maxdepthund verwenden -type f, um dieses Problem zu vermeiden.

Antwort2

Es scheint, als würden Sie versuchen, jeden einzelnen Befehl mit auszuführen -exec. Dies würde im Allgemeinen nicht funktionieren, da -execnur externe Befehle ausgeführt werden.

Rufen Sie stattdessen ein einzelnes Inline-Skript auf und lassen Sie es findals Generator für eine Schleife in diesem Skript fungieren:

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

Dies würde alle regulären Dateien im oder unterhalb des rootfsVerzeichnisses finden. Für Stapel dieser Dateien sh -cwird ein kurzes Inline-Skript aufgerufen. Dieses Skript kopiert jede Datei in das angegebene Verzeichnis, gibt für jede erfolgreich kopierte Datei einen Punkt gefolgt von einem Zeilenumbruch aus und ruft auf sync.

Zählt wc -ldie Anzahl der ausgegebenen Punkte und meldet diese Anzahl. Wir zählen nicht die Pfadnamen selbst, da diese Zählung irreführend wäre, wenn ein Pfadname ein eingebettetes Zeilenumbruchzeichen enthält.

Ohne die Verwendung findkann dies beispielsweise wie folgt erfolgen bash:

shopt -s globstar dotglob nullglob

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

Dies verwendet ein Globbing-Muster, das den **Glob enthält, der mit Unterverzeichnissen übereinstimmt, wenn die globstarShell-Option gesetzt ist. Ich habe es auch so eingestellt, dotglobdass versteckte Namen angezeigt werden können, und die nullglobShell-Option, um die Ausführung der Schleife ganz zu vermeiden, wenn das Muster mit nichts übereinstimmt.

Dasselbe, aber mit einem Zähler:

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"

verwandte Informationen