LINUX.ORG.RU

Прогресс-бар Zenity для dd

 , ,


0

2

Добрый день! Помогите, пожалуйста, прикрутить прогресс-бар Zenity к команде создания загрузочного диска?

Использую команду:

dd bs=4M if=iso-файл of=/dev/sdX status=progress

Я находил несколько примеров, но ни один из них не смог адаптировать. По сути, при записи dd первой цифрой выводит количество записанных байт - их нужно как-то выцепить и передать на расчет процентов, например, такой командой:

echo $(( 100*$byte_writed/$byte_total ))

Итоговое количество байт считается по команде:

du -sb "iso-файл" | awk '{print $1}'

Но вот как это все подружить друг с другом? Вот такая у меня конструкция, которая не работает:

total=`du -sb 'iso-файл' | awk '{print $1}'`
echo "Total size $total"

sudo dd bs=4M if=iso-файл of=/dev/sdX status=progress 2>1.txt | while read f
do
	writed=`cat 1.txt | tail -n 1 | cut -d' ' -f1`
	echo $(( 100*$writed/$total ))
done | zenity --progress --title="bla" --text="blabla..." --percentage=0

P.S.: есть множество утилит с интерфейсом для создания загрузочных флешек, но хотелось бы использовать встроенные средства.



Последнее исправление: n1GT (всего исправлений: 1)

Ответ на: комментарий от krasnh

Я эту штуку даже запустить не смог, ошибку выдала :) easydd: 169: [: gui: unexpected operator easydd: 183: [: gui: unexpected operator easydd: 194: [: gui: unexpected operator easydd: 215: [: unexpected operator easydd: 1: gtkdialog: not found

Да и сам скрипт выглядит сложным. Хочется более легкого, пускай и не такого функционального, решения. Для профессионального использования, конечно, лучше специальное приложение использовать, но это не мой случай.

n1GT
() автор топика

если периодически посылать процессу dd kill USR1 - то он будет выплевывать текущую статистику. План действий наверно примерно такой:

  • запустить процесс
  • например через pidof, получить пид процесса
  • посылать в цикле kill USR1 на этот пид и читать вывод
  • через awk - получить сколько считал и сколько осталось
  • результат запихнуть в zenity
Silerus ★★★★
()
Ответ на: комментарий от Silerus

Запускаю процесс, нахожу пид. Параллельно в другом окне терминала делаю «kill USR1 121716», на что мне сообщения: bash: kill: USR1: аргументами должны быть идентификаторы процессов или заданий bash: kill: (121716) - Операция не позволена

n1GT
() автор топика
Ответ на: комментарий от anonymous

pv не установлен. Задачка - использовать только встроенные средства, а их - Zenity и dd.

На самом деле, ничего сложного нет. Надо только понять, как.

Последнее, до чего я дошел:

cd="файл.iso"
output="/dev/sda"
cdsize="2129752064"

x=1
sudo dd if=$cd of=$output status=progress 2>1.txt | ( while [ $x -lt 100 ]
do
  echo $x
  current=`cat 1.txt | tail -n 1 | cut -d' ' -f1`
  x=$(( $current * 100 / $cdsize ))
  sleep 1
done ) | zenity --progress --title="Copy files progress" --text="Copying files to $output..." --percentage=0

Но при этом, для установки переменной current почему-то не перечитывается файл 1.txt - как будто он один раз прочитался, и все. А он же дополняется, и цифры совсем другие каждую секунду в последней строке.

n1GT
() автор топика

Кстати, почитайте документацию к clonezilla - там можно задействовать собственные скрипты, возможно - это более простой способ решить вашу задачу.

Silerus ★★★★
()
Ответ на: комментарий от Silerus

Я могу вывести прогресс этой командой в окно терминала, в котором выполняется скрипт. Но не могу затолкать это в переменную.

Дело в принципе даже не столько в dd, сколько в самом алгоритме - как передать изменяющиеся значения вывода в переменную.

  • Выводить в файл для использования cat не получается, он не перечитывается.
  • Брать напрямую с помощью kill тоже не получается.

И дело даже не в Zenity. Не получается в принципе вывод затолкать в переменную.

Clonezilla также не подходит. У меня условия - замкнутая среда. Есть только dd и только Zenity.

n1GT
() автор топика
Ответ на: комментарий от n1GT

файл 1.txt

нахрена, а главное - зачем?

как насчет попробовать (мне лень. пишу по памяти)

sudo dd if=$cd of=$output status=progress | while read -r ddProgress; do

# тут чота с ${ddProgress}
done
#дальше - как у тебя было
aol ★★★★★
()
Последнее исправление: aol (всего исправлений: 1)
Ответ на: комментарий от n1GT

пример от лисяры

#!/bin/sh

IF=/dev/ad0
OF=/home/zg/1.bin
COUNT=400
BLOCK=1m

CMD="dd if=${IF} of=${OF} bs=${BLOCK} count=${COUNT}"

progress() {
  while read line; do
    if [ -n "`echo $line | grep transfe`" ]; then
      echo -e "\e[1FCopying: $line"
    fi
  done
}

echo '**********************'
echo "IF: ${IF}"
echo "OF: ${OF}"
echo "Block: ${BLOCK}"
echo "Count: ${COUNT}"
echo '**********************'
echo Copying:
echo -n "Please wait ... "

($CMD 2>&1 | progress) &

while true; do
  sleep 1
  PID=`pgrep dd`
  if [ -z "${PID}" ]; then break; fi
  kill -INFO ${PID}
done

wait

echo "Operation complete!"
Silerus ★★★★
()
Ответ на: комментарий от Silerus

В общем, долго я копался и пришел к двум выводам:

  1. Парсить вывод dd это безумие;
  2. Временный файл все же нужен, буду использовать его как лог записи.

В итоге, у меня получилась вот такая конструкция, в комментариях описаны все мои мытарства:

pkexec dd bs=$bs_param if=$img_file of=$usb_disk status=progress 2>$tmp_file | while [ "$bar" -lt "100" ]
do
	echo $bar
	# Так как dd ставит символы возврата каретки в конце строки
	# вместо символа новой строки, применяется извращенный парсинг:
	# - Отбросить строки со словом "records" (появляются в конце записи);
	# - Перевернуть все символы задом-наперед (для возможности взять предпоследнее
	#     вхождение строки в обычном порядке если использовать разделитель "/");
	# - Взять второе вхождение (предпоследнее вхождение строки);
	# - Перевернуть все символы задом-наперед (вернуть порядок символов);
	# - Убрать символы возврата каретки (тогда 2 итоговые строки станут одной);
	# - Убрать "s " в конце строки (появляется при пересчете dd с MiB на GiB);
	# - Взять только последнюю строку для следуюещей обработки (после последней
	#     строкой процесса записи - перед строками "records" и далее, используются
	#     обычные символы новой строки, поэтому в выводе образуется две строки);
	# - Убрать символ "s" в начале строки (убрать его из числа байт);
	# - Отбросить все вхождения строки, кроме числа записанных байт.
	bar=$(echo `cat $tmp_file | grep -v "records" | rev | cut -d"/" -f2 | rev | tr -d '\r' | sed "s/s //g" | tail -n1 | sed "s/^s//" | cut -d" " -f1`)
	echo $bar >> /dev/null
	bar=$(( bar * 100 / img_size ))
	sleep 1
done | zenity --progress --title="$title" --text="Пожалуйста, подождите.\nРаспаковка образа «$img_name»...\n" --auto-close --no-cancel --percentage=0
sync | zenity --progress --title="$title" --text="Пожалуйста, подождите.\nЗавершение записи на USB-носитель...\n" --auto-close --no-cancel --pulsate

Все работает, как часы! Проверку по хэшу также прикрутил (сюда не копировал).

Остается только понять риски изменения параметра bs для dd. По умолчанию он 512 байт, при этом скорость записи на диск 16 Мб/сек. А если установить хотя бы на 1M, то скорость записи на диск уже 50 Мб/сек. Вот и думаю, чем чревато… Все равно же проверка по хэшу есть.

n1GT
() автор топика