Предыдущий код:
total=`ls -Rp rootfs | wc -l`
count=0
Когда я присваиваю простое сложение переменной:
sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=$((count+1)) \; -exec echo -en "\rcopiati: $count/$total" \;
Я получил:
find: ‘count=1’: No such file or directory
Также, когда я исполняю:
sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=1 \; -exec echo -en "\rcopiati: $count/$total" \;
У меня та же ошибка. Почему?
Для каждого скопированного файла мне нужен счетчик: 1/13444, который обновляется до 2/13444, 3/13444 и т. д.
редактировать:
Я нашел метод, но он не видит скрытые файлы. Как мне заставить их увидеть их в цикле?
#!/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
решение1
Оболочка расширяется count=$((count+1))
перед запуском find
.
Затем find
попытается выполнить аргумент -exec
как команду. Это должна быть программа или скрипт, это не может быть встроенная оболочка или синтаксис оболочки для назначения переменных.
Подсчет найденных файлов таким образом не работает, поскольку find
запускает новый процесс для -exec
, поэтому результат назначения переменной не будет доступен в родительской оболочке.
Я предлагаю вывести строку для каждого найденного файла и передать вывод в find
, wc -l
например
find rootfs -exec cp -d -- "{}" "/media/$USER/{}" \; -exec sync \; -print|wc -l
Чтобы получить какой-то вывод при копировании файлов, можно использовать что-то вроде этого:
find rootfs|while IFS= read -r file
do
cp -d -- "$file" "/media/$USER/$file"
sync
count=$((count+1))
echo -en "\rcopiati: $count/$total"
done
Замечания:
Это не работает для имен файлов, содержащих символ новой строки (и, возможно, другие специальные символы).
Скрипт может не работать, если rootfs
содержит подкаталоги. Вам следует либо обработать этот случай, либо использовать find
опции -maxdepth
и , -type f
чтобы избежать этой проблемы.
решение2
Кажется, вы пытаетесь выполнить каждую команду с помощью -exec
. В общем случае это не сработает, так как -exec
выполняет только внешние команды.
Вместо этого вызовите один встроенный скрипт и позвольте ему find
действовать как генератор для цикла в этом скрипте:
find rootfs -type f -exec sh -c '
for pathname do
cp -d "$pathname" "/media/$USER" &&
echo . &&
sync
done' sh {} + | wc -l
Это найдет все обычные файлы в rootfs
каталоге или ниже. Для пакетов этих файлов sh -c
вызывается короткий встроенный скрипт. Этот скрипт копирует каждый файл в указанный каталог, выводит точку, за которой следует новая строка для каждого успешно скопированного файла, и вызывает sync
.
Подсчитывает wc -l
количество выведенных точек и сообщает это число. Мы не подсчитываем сами имена путей, поскольку это число может ввести в заблуждение, если какое-либо имя пути содержит встроенный символ новой строки.
Без использования find
это можно сделать, например bash
, так:
shopt -s globstar dotglob nullglob
for pathname in rootfs/**/*; do
[[ ! -f $pathname ]] && continue
cp -d "$pathname" "/media/$USER" &&
echo . &&
sync
done | wc -l
Это использует шаблон подстановки, содержащий **
glob, который соответствует подкаталогам inte, если globstar
установлена опция shell. Я также установил dotglob
возможность видеть скрытые имена и nullglob
опцию shell, чтобы вообще не запускать цикл, если шаблон ничему не соответствует.
То же самое, но со счетчиком:
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"