Как автоматически обнаружить и записать на USB с переменными пробелами в его имени

Вопрос или проблема

Я выполняю второе задание по BASH из Руководства по написанию сценариев на Bash TLDP, и мне удалось разобраться с большинством задач, пока не дошло до момента, когда нужно копировать сжатые файлы на вставленную флешку USB.

Список домашнего каталога

Выполните рекурсивный список каталогов в домашнем каталоге пользователя и сохраните информацию в файл. Сожмите файл, заставьте скрипт попросить пользователя вставить флешку USB, затем нажать ENTER. Наконец, сохраните файл на флешке после того, как убедитесь, что флешка правильно смонтирована, проанализировав вывод команды df. Обратите внимание, что флешку нужно размонтировать перед тем, как ее удалить.

По мере того как я продвигаюсь в написании скрипта, он становится все менее … элегантным, и мне интересно, есть ли более лучший способ сделать это. Я понимаю, что создание файлов, вероятно, не самый эффективный способ провести сравнения, но пока не разобрался с расширениями оболочки, и планирую изменить их, как только добьюсь работоспособности.

Проблема конкретно в том, чтобы убедиться, что USB смонтирован и что я записываю на флешку USB, а не куда-то еще. Я сравниваю последнюю строку df после подключения USB с последней строкой df из diff между df до подключения USB и df после его подключения и перемещаюсь в цикле, пока они не совпадут. К сожалению, результат diff начинается с >, но я намерен использовать sed, чтобы от него избавиться. Реальная проблема в том, что путь к тому месту, где смонтирована моя флешка USB, следующий:

/media/flerb/”Название USB с пробелами”

Чтобы сделать это портативным для USB, которые могут иметь разные имена, мне, возможно, стоит сделать что-то с awk и разделителями полей? И как продолжение, я знаю, что это довольно неэлегантно, и меня интересует, есть ли более чистый способ решить эту задачу … особенно потому, что это второе задание и все еще на УРОВНЕ ЛЕГКО.

Вывод из df в конце:

/dev/sdb1                     15611904  8120352   7491552  53% /media/flerb/CENTOS 7 X8
> /dev/sdb1                     15611904  8120352   7491552  53% /media/flerb/CENTOS 7 X8

Скрипт на данный момент

 1 #!/bin/bash
  2 
  3 if [ "$UID" -eq 0 ] ; then
  4         echo "Не запускайте это от имени root"
  5         exit 1
  6 fi
  7 
  8 #Создайте резервную копию с заголовком с датой в резервной директории
  9 BACKUP_DIR="$HOME/backup"
 10 DATE_OF_COPY=$(date --rfc-3339=date)
 11 BACKUP_FILE="$BACKUP_DIR/$DATE_OF_COPY"
 12 
 13 [ -d "$BACKUP_DIR" ] || mkdir -m 700 "$BACKUP_DIR"
 14 
 15 #найдите все файлы рекурсивно в домашнем каталоге $HOME
 16 find -P $HOME >> "$BACKUP_FILE"
 17 
 18 #используйте lzma для сжатия
 19 xz -zk --format=auto --check=sha256 --threads=0 "$BACKUP_FILE"
 20 
 21 #создание файлов для операций
 22 BEFORE="$BACKUP_DIR"/before_usb.txt
 23 AFTER="$BACKUP_DIR"/after_usb.txt
 24 DIFFERENCE="$BACKUP_DIR"/difference.txt
 25 
 26 df > "$BEFORE"
 27 read -p 'Вставьте USB и нажмите любую кнопку' ok
 28 sleep 2
 29 df > "$AFTER"
 30 diff "$BEFORE" "$AFTER" > "$DIFFERENCE"
 31 sleep 2
 32 echo
 33 
 34 TAIL_AFTER=$(tail -n 1 "$AFTER")
 35 TAIL_DIFF=$(tail -n 1 "$DIFFERENCE")
 36 
 37 until [ "$TAIL_AFTER" == "$TAIL_DIFF" ] ;
 38 do
 39         echo "Еще не время"
 40         df > "$AFTER"
 41         TAIL_AFTER=$(tail -n 1 "$AFTER")
 42         diff "$BEFORE" "$AFTER" > "$DIFFERENCE"
 43         TAIL_DIFF=$(tail -n 1 "$DIFFERENCE")
 44         echo "$TAIL_AFTER"
 45         echo "$TAIL_DIFF"
 46         sleep 1
 47 
 48 done
 49 exit $?

Чтобы получить правильный USB и его путь:

  • заметил, что первый USB, подключенный к моей системе, смонтирован на файловой системе /dev/sdb1, а второй – на файловой системе /dev/sdc1. Я добавил раздел, чтобы переключаться на /dev/sdc1, если udevadm info -q all -n "/dev/sdb" | grep "ID_BUS=usb" возвращает true.

  • если diff между df --output=target | grep "/media/darren" до и после содержит “/media/darren”, то это, предположительно, новый USB. USB смонтирован.

  • if udevadm info -q all -n "/dev/sdb" | grep "ID_BUS=usb" истинно, то это устройство, смонтированное на “/dev/sdb”, является usb устройством.

  • чтобы получить путь и убедиться, что я захватываю нужный: df --output=source,avail,target | grep "$FILESYSTEM" | grep "$MOUNTPOINT" и некоторые очень красивые awk

    udevadm info -q all -n "$FILESYSTEM" | grep "ID_BUS=usb" > $RESULT
    USB_ADDR="$BACKUP_DIR"/usb_addr.txt
    if grep "ID_BUS=usb" "$RESULT" ; then
        df --output=source,avail,target | grep "$FILESYSTEM" | grep "$MOUNTPOINT" > "$USB_ADDR"
        awk -i inplace '{$0=gensub(/\s*\S+/,"",1)}1' "$USB_ADDR"
        awk -i inplace '{$0=gensub(/\s*\S+/,"",1)}1' "$USB_ADDR"
        sed -i 's/^ *//' "$USB_ADDR"
    

К сожалению, процесс diff не срабатывает, если добавляются или удаляются другие элементы. Но, по крайней мере, он завершает работу корректно, если захватывает неправильное устройство при использовании отфильтрованного вывода df и grep для файловой системы и точки монтирования.

Пробовал awk 'NR!=1{print $NF}' <(df)|sort. Все еще не очень силен в расширениях bash.

#!/bin/bash

if [ "$UID" -eq 0 ] ; then
        echo "Не запускайте это от имени root"
        exit 50
fi

#Создайте резервную копию с заголовком с датой в резервной директории
BACKUP_DIR="$HOME/backup"
DATE_OF_COPY=$(date --rfc-3339=date)
BACKUP_FILE="$BACKUP_DIR/$DATE_OF_COPY"

[ -d "$BACKUP_DIR" ] || mkdir -m 700 "$BACKUP_DIR"

#найдите все файлы рекурсивно в домашнем каталоге $HOME
find -P $HOME >> "$BACKUP_FILE"

#используйте lzma для сжатия
xz -zk --format=auto --check=sha256 --threads=0 "$BACKUP_FILE"

#создание файлов для операций по информации до и после вставки usb и разности между ними
#это часть того, как мы будем удостоверяться, что мы записываем на правильное устройство
BEFORE="$BACKUP_DIR"/before_usb.txt
AFTER="$BACKUP_DIR"/after_usb.txt
DIFFERENCE="$BACKUP_DIR"/difference.txt
#MOUNTPOINT=где компьютер по умолчанию монтирует USB
MOUNTPOINT="/media/darren"
FILESYSTEM="/dev/sdb"
RESULT="$BACKUP_DIR"/result.txt


#если на точке монтирования что-то есть до подключения флешки, мы хотим это знать
#чтобы записать на новое устройство
udevadm info -q all -n "$FILESYSTEM" | grep "ID_BUS=usb" > $RESULT
if grep "ID_BUS=usb" "$RESULT" ; then
        FILESYSTEM="/dev/sdc"
        echo $FILESYSTEM
fi        

df --output=target | grep $MOUNTPOINT > "$BEFORE"

read -p 'Вставьте USB или жесткий диск и нажмите любую кнопку' ok

df --output=target | grep $MOUNTPOINT > "$AFTER"
#diff для поиска нового
diff "$BEFORE" "$AFTER" > "$DIFFERENCE"

# Ищем на точке монтирования в разности между выводами df до и после
SEARCH_FOR_MOUNT=$(grep "$MOUNTPOINT" "$DIFFERENCE")

until [ "$SEARCH_FOR_MOUNT" ] ;
do
        df --output=target | grep $MOUNTPOINT > "$AFTER"
        diff "$BEFORE" "$AFTER" > "$DIFFERENCE"
        SEARCH_FOR_MOUNT=$(grep "$MOUNTPOINT" "$DIFFERENCE")

done
#проверяем, подключено ли новое устройство в файловую систему является ли это USB
udevadm info -q all -n "$FILESYSTEM" | grep "ID_BUS=usb" > $RESULT
USB_ADDR="$BACKUP_DIR"/usb_addr.txt
if grep "ID_BUS=usb" "$RESULT" ; then
        df --output=source,avail,target | grep "$FILESYSTEM" | grep "$MOUNTPOINT" > "$USB_ADDR"
        awk -i inplace '{$0=gensub(/\s*\S+/,"",1)}1' "$USB_ADDR"
        awk -i inplace '{$0=gensub(/\s*\S+/,"",1)}1' "$USB_ADDR"
        sed -i 's/^ *//' "$USB_ADDR"

        if [ ! -s $USB_ADDR ] ; then
              echo "Ошибка при поиске адреса USB"
              exit 100


        ADDR=$(cat "$USB_ADDR")
        cp "$BACKUP_FILE.xz" "$ADDR"
        rm "$BACKUP_FILE" "$USB_ADDR" "$RESULT" "$BEFORE" "$AFTER" "$DIFFERENCE"

else
        echo "Устройство не является USB"
        exit 52
fi

exit $?

Ответ или решение

Автоматическое определение и запись на USB с переменными пробелами в его названии

Введение

В этой статье мы рассмотрим, как написать bash-скрипт, который позволяет автоматически определять USB-накопитель с учетом переменных пробелов в его названии, а также сохранять на него сжатый файл с информацией о пользователе. Учитывая важные моменты, такие как монтирование устройства, мы обеспечим надежное выполнение сценария без рисков записи на другие накопители.

Шаг 1: Понимание структуры скрипта

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

Шаг 2: Определение USB-накопителя

Для определения USB-накопителя нам нужно учитывать, что его имя может содержать пробелы. Мы можем использовать команду df для получения информации о подключенных устройствах. Тем не менее, вместо того чтобы сравнивать полные строки, эффективнее будет использовать awk для извлечения нужных полей.

Как только USB будет вставлен, вы можете использовать следующую конструкцию для получения названия файловой системы:

NEW_USB=$(df -h --output=target | awk '/\/media\/.*[a-zA-Z0-9]/ {print; exit}')

Эта команда будет извлекать первую строку, соответствующую подключенному USB-устройству.

Шаг 3: Параметры монтирования

Скрипт должен проверять, действительно ли устройство USB смонтировано. После нажатия клавиши Enter для подтверждения вставки накопителя мы сравниваем текущее состояние монтирования с предыдущим.

Шаг 4: Запись на USB-накопитель

Используя переменную NEW_USB, мы можем безопасно создать резервную копию. Если название устройства содержит пробелы, его необходимо обрамить в кавычки, чтобы избежать проблем с синтаксисом в bash:

cp "$BACKUP_FILE.xz" "$NEW_USB"

Полный пример скрипта

Вот полная версия скрипта, учитывающая все описанные выше аспекты:

#!/bin/bash

# Проверьте, что вы не запускаете скрипт от имени root
if [ "$UID" -eq 0 ]; then
    echo "Не запускайте этот скрипт с правами root"
    exit 1
fi

# Создание резервного файла
BACKUP_DIR="$HOME/backup"
DATE_OF_COPY=$(date +%F)
BACKUP_FILE="$BACKUP_DIR/$DATE_OF_COPY"

mkdir -p -m 700 "$BACKUP_DIR"
find -P $HOME > "$BACKUP_FILE"
xz -zk --format=auto "$BACKUP_FILE"

# Сохранение состояния монтирования до вставки USB
BEFORE_MOUNT=$(df -h --output=target | awk '/\/media\/.*[a-zA-Z0-9]/')

read -p 'Вставьте USB и нажмите Enter...' ok

# Сохранение состояния монтирования после вставки USB
AFTER_MOUNT=$(df -h --output=target | awk '/\/media\/.*[a-zA-Z0-9]/')

while [ "$BEFORE_MOUNT" == "$AFTER_MOUNT" ]; do
    sleep 1
    AFTER_MOUNT=$(df -h --output=target | awk '/\/media\/.*[a-zA-Z0-9]/')
done

# Получение названия нового USB
NEW_USB=$(df -h --output=target | awk '/\/media\/.*[a-zA-Z0-9]/ {print; exit}')

# Копирование сжатого файла на USB
if [ -n "$NEW_USB" ]; then
    cp "$BACKUP_FILE.xz" "$NEW_USB"
    echo "Резервная копия успешно создана на $(basename "$NEW_USB")"
else
    echo "Не удалось определить USB-накопитель."
    exit 1
fi

exit 0

Заключение

Создание сценария для автоматического детектирования USB-накопителей с учетом пробелов в названиях является полезной задачей для автоматизации процессов резервного копирования. Этот скрипт поддерживает основной функционал и может быть расширен для более сложных операций, в зависимости от ваших потребностей.

Оцените материал
Добавить комментарий

Капча загружается...