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 find
wird 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 find
für einen neuen Prozess ein neuer Prozess gestartet wird -exec
und 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 find
an 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 rootfs
Unterverzeichnisse enthalten sind. Sie sollten diesen Fall entweder selbst behandeln oder find
die Optionen -maxdepth
und 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 -exec
nur externe Befehle ausgeführt werden.
Rufen Sie stattdessen ein einzelnes Inline-Skript auf und lassen Sie es find
als 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 rootfs
Verzeichnisses finden. Für Stapel dieser Dateien sh -c
wird 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 -l
die 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 find
kann 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 globstar
Shell-Option gesetzt ist. Ich habe es auch so eingestellt, dotglob
dass versteckte Namen angezeigt werden können, und die nullglob
Shell-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"