Unix & Linux Asked by flerb on January 29, 2021
I am doing the second BASH exercise from TLDP Bash-Scripting Guide, and I have most of it figured out up until the part when it comes time to copy the compressed files to an inserted USB.
Home Directory Listing
Perform a recursive directory listing on the user’s home directory and save the information to a file. Compress the file, have the script
prompt the user to insert a USB flash drive, then press ENTER.
Finally, save the file to the flash drive after making certain the
flash drive has properly mounted by parsing the output of df. Note
that the flash drive must be unmounted before it is removed.
As I progress with the script it is becoming less ..elegant, and was wondering if there was a better way to do this. I know creating files is likely not the most efficient way to do the comparisons, but have not got the shell expansions figured yet, and intend to change those once I get it working.
The problem specifically is, to ensure that the usb is mounted and that I am writing to the USB and nowhere else. I am comparing the last line of df
after the USB is plugged in with the last line of df
from the diff
between df
before USB is plugged in and df
after USB is plugged in, and looping until they match. Unfortunately, the diff
result starts with a >, but I intend to use sed to get rid of that. The real problem is the path to where my usb is mounted is:
/media/flerb/”Title of USB with spaces”
To make this portable for USBs that may have different names is my best bet from here to do something with awk and field separators? And as a follow-up, I know this is pretty inelegant, and wonder if there is a cleaner way to go about this…especially because this is the second exercise and still in EASY.
The output from the df tails is:
/dev/sdb1 15611904 8120352 7491552 53% /media/flerb/CENTOS 7 X8
> /dev/sdb1 15611904 8120352 7491552 53% /media/flerb/CENTOS 7 X8
The script so far
1 #!/bin/bash
2
3 if [ "$UID" -eq 0 ] ; then
4 echo "Don't run this as root"
5 exit 1
6 fi
7
8 #Create a backup file with the date as title in a backup directory
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 #find all files recursively in $HOME directory
16 find -P $HOME >> "$BACKUP_FILE"
17
18 #use lzma to compress
19 xz -zk --format=auto --check=sha256 --threads=0 "$BACKUP_FILE"
20
21 #making files to use in operations
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 'Enter USB and press any button' 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 "Not yet"
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 $?
To get the right USB and it's path:
noticed that the first USB plugged into my system is mounted on the /dev/sdb1 filesystem and the second is mounted on the /dev/sdc1 filesystem. I added a section to switch to /dev/sdc1 if udevadm info -q all -n "/dev/sdb" | grep "ID_BUS=usb"
returned true.
if diff
between df --output=target | grep "/media/darren"
before and after has "/media/darren" in it, that's presumably the new USB. USB is mounted.
if udevadm info -q all -n "/dev/sdb" | grep "ID_BUS=usb
is true then that device mounted on "/dev/sdb" is a usb device
to get the path, and make sure I was grabbing the right one: df --output=source,avail,target | grep "$FILESYSTEM" | grep "$MOUNTPOINT"
and some really nice 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"
Unfortunately diffing fails if other stuff is added or removed. But, at least it fails nicely if it grabs the wrong device when using the df
filtered output and grepping for the filesystem and mountpoint.
Tried awk 'NR!=1{print $NF}' <(df)|sort
. Still not great on bash expansions.
#!/bin/bash
if [ "$UID" -eq 0 ] ; then
echo "Don't run this as root"
exit 50
fi
#Create a backup file with the date as title in a backup directory
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"
#find all files recursively in $HOME directory
find -P $HOME >> "$BACKUP_FILE"
#use lzma to compress
xz -zk --format=auto --check=sha256 --threads=0 "$BACKUP_FILE"
#making files to use in operations of before and after usb is inserted info and diff between them
#this is part of how we will insure that we are writing to the correct device
BEFORE="$BACKUP_DIR"/before_usb.txt
AFTER="$BACKUP_DIR"/after_usb.txt
DIFFERENCE="$BACKUP_DIR"/difference.txt
#MOUNTPOINT=where computer mounts USBs by default
MOUNTPOINT="/media/darren"
FILESYSTEM="/dev/sdb"
RESULT="$BACKUP_DIR"/result.txt
#if there is something on the mountpoint before we plug in the usb, we want to know
#so the new device is written to
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 'Enter USB or hard drive and press any button' ok
df --output=target | grep $MOUNTPOINT > "$AFTER"
#dif them to find the new one
diff "$BEFORE" "$AFTER" > "$DIFFERENCE"
# Look in mountpoint in the difference between the before and after df outputs
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
#check if new device plugged into filesystem is a 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 "Error finding USB Address"
exit 100
ADDR=$(cat "$USB_ADDR")
cp "$BACKUP_FILE.xz" "$ADDR"
rm "$BACKUP_FILE" "$USB_ADDR" "$RESULT" "$BEFORE" "$AFTER" "$DIFFERENCE"
else
echo "Device is not a USB"
exit 52
fi
exit $?
Answered by flerb on January 29, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP