How to check if filepath is mounted in OS X using bash? - macos

How do I perform the mount only if it has not already been mounted?
This is on OS X 10.9 and this is what I have currently:
#!/bin/bash
# Local mount point
LOCALMOUNTPOINT="/folder/share"
# Perform the mount if it does not already exist
if ...
then
/sbin/mount -t smbfs //user:password#serveraddress/share $LOCALMOUNTPOINT
else
echo "Already mounted"
fi

While #hd1's answer gives you whether the file exists, it does not necessary mean that the directory is mounted or not. It is possible that the file happen to exist if you use this script for different machines or use different mount points. I would suggest this
LOCALMOUNTPOINT="/folder/share"
if mount | grep "on $LOCALMOUNTPOINT" > /dev/null; then
echo "mounted"
else
echo "not mounted"
fi
Note that I include "on" in grep statement based on what mount command outputs in my machine. You said you use MacOS so it should work, but depending on what mount command outputs, you may need to modify the code above.

This is what I use in my shell scripts on OS X 10.7.5
df | awk '{print $6}' | grep -Ex "/Volumes/myvolume"
For OS X 10.10 Yosemite I have to change to:
df | awk '{print $9}' | grep -Ex "/Volumes/myvolume"

For me from this solution in stackoverflow_QA_Check if a directory exists in a shell script
[ -d /Volumes/ ] && echo "Already mounted /Volumes/ in OS X" || echo "Not mounted"
to use that
# 2 lines
$LOCALMOUNTPOINT="/folder/share" ;
[ -d $LOCALMOUNTPOINT ] && echo "Already mounted $LOCALMOUNTPOINT in OS X" || /sbin/mount -t smbfs //user:password#serveraddress/share $LOCALMOUNTPOINT
Here is Stackoverflow_QA_how-can-i-mount-an-smb-share-from-the-command-line
additional link about smb which I don't know well
# Here is my solution
$LOCALMOUNTPOINT="/folder/share" ;
[ ! -d $LOCALMOUNTPOINT ] && mkdir $LOCALMOUNTPOINT && /sbin/mount -t smbfs //user:password#serveraddress/share $LOCALMOUNTPOINT || echo already mounted $LOCALMOUNTPOINT
I have to make new folder for my SMOOTH use before mounting that.
so I added mkdir $LOCALMOUNTPOINT
Thank you I learned a lot with this case.
Have A nice day!!! ;)

Related

How to use mkfs -t ext4 to keep data on existing volume but delete on new?

I am attaching block volume in OCI to a new or existing instance using a script (below). However, if the volume already has a file system type already assigned I will lose all my data!
Is there a way only to run the command sudo mkfs -t ext4 /dev/oracleoci/oraclevdb only if it's not already formatted?
Is there a way to run line 1 below, only if the attached volume is not already formatted?
sudo mkfs -t ext4 /dev/oracleoci/oraclevdb
sudo mkdir /data
sudo mount /dev/oracleoci/oraclevdd /data
df -h
The issue is every time a new instance is created using an existing volume, I lose all my data. However, I want to keep the behaviour for new instances were attaching a new volume.
So something like...
if condition x
sudo mkfs -t ext4 /dev/oracleoci/oraclevdb
else
do nothing
I'm running Oracle Linux 8.
Just check if you can mount it.
if ! sudo mount /dev/oracleoci/oraclevdd /data; then
if ! sudo mkfs -t ext4 /dev/oracleoci/oraclevdb; then
echo "och nooo, formatting fialed"
fi
if ! sudo mount /dev/oracleoci/oraclevdd /data; then
echo "Och nooooo, can't mount after formatting, that's odd"
fi
fi
You can get this info running lsblk like so:
lsblk -o NAME,FSTYPE
and run a test using some script:
export DEVICE="/dev/oracleoci/oraclevdb"
export FSTYPE="ext4"
if ! lsblk -o NAME,FSTYPE | grep $DEVICE | grep $FSTYPE; then
sudo mkfs -t $FSTYPE $DEVICE
fi
You could use file to check for content of anything:
with option:
-b, --brief
Do not prepend filenames to output lines (brief mode).
-L, --dereference
option causes symlinks to be followed, as the like-named option in ls
-s, --special-files
Specifying the -s option causes file to also read argument files which
are block or character special files.
Create a script conditionalMkExt4:
#!/bin/bash
if [[ ! -b $1 ]] ;then
echo "Not a block device: '$1'"
exit 1
fi
sudo /bin/bash <<eof
read -r partTyp < <(file -Lsb "$1")
case \$partTyp in
data )
mkfs -t ext4 "$1"
;;
* )
echo "Device '$1' is of type: '\$partTyp'"
exit 1
;;
esac
if [[ $2 ]] ;then
[[ -e $2 ]] || mkdir -p "$2"
mount "$1" "$2"
fi
eof
Then
conditionalMkExt4 /dev/oracleoci/oraclevdb /data
If you want to be able to whipe any non ext4 partition:
Juste replace case ... esac by
case \$partTyp in
*ext4* )
echo "Device '$1' already formated as ext4"
exit 1 # Comment this if you want to mount if already formated
;;
* )
mkfs -t ext4 "$1"
;;
esac

How do I get USB device info from a script running within a Docker container in a bash script?

I made a mount.sh file inspired by balena-storage. It works when I login to the container via the balena.io dashboard where I'm deploying (could be the same elsewhere) and run the script manually. It hangs with unpopulated variables when the container runs the script when starting (a script that runs the script). I think it’s a permissions issue or script running script thing. I'm not sure how to proceed in reading USB device variables.
mount.sh:
# Automatically mount a USB drive by specified volume name.
# Note: make sure to have USB_VOLUME_NAME set in env vars.
# Thanks: https://github.com/balena-io-playground/balena-storage
echo "Checking for USB_VOLUME_NAME..."
echo "A"
if [[ -z $USB_VOLUME_NAME ]]; then
echo "Make sure to set environment variable USB_VOLUME_NAME in order to find a connected USB drive by that label and connect to it. Exiting..." >> /usr/src/app/mount.log
exit 1
fi
echo "B"
# Get device by label env var set in balena.io dashboard device env vars
USB_DEVICE=$(blkid -L $USB_VOLUME_NAME)
if [[ -z $USB_DEVICE ]]; then
echo "Invalid USB_DEVICE name: $USB_DEVICE" >> /usr/src/app/mount.log
exit 1
fi
echo $USB_DEVICE
echo "C"
# Get extra device info
ID_FS_TYPE=${ID_FS_TYPE:=$(/bin/udevadm info -n $USB_DEVICE | /usr/bin/awk -F "=" '/ID_FS_TYPE/{ print $2 }')}
ID_FS_UUID_ENC=${ID_FS_UUID_ENC:=$(/bin/udevadm info -n $USB_DEVICE | /usr/bin/awk -F "=" '/ID_FS_UUID_ENC/{ print $2 }')}
ID_FS_LABEL_ENC=${ID_FS_LABEL_ENC:=$(/bin/udevadm info -n $USB_DEVICE | /usr/bin/awk -F "=" '/ID_FS_LABEL_ENC/{ print $2 }')}
MOUNT_POINT=/mnt/$USB_VOLUME_NAME
echo $ID_FS_TYPE
echo $ID_FS_UUID_ENC
echo $ID_FS_LABEL_ENC
echo $MOUNT_POINT
echo "D"
# Bail if file system is not supported by the kernel
if ! /bin/grep -qw $ID_FS_TYPE /proc/filesystems; then
echo "File system not supported: $ID_FS_TYPE" >> /usr/src/app/mount.log
exit 1
fi
echo "E"
# Mount device
if /bin/findmnt -rno SOURCE,TARGET $USB_DEVICE >/dev/null; then
echo "Device $USB_DEVICE is already mounted!" >> /usr/src/mount.log
else
echo "Mounting - Source: $USB_DEVICE - Destination: $MOUNT_POINT" >> /usr/src/app/mount.log
/bin/mkdir -p $MOUNT_POINT
/bin/mount -t $ID_FS_TYPE -o rw $USB_DEVICE $MOUNT_POINT
fi
echo "F"
When the container runs the script, it gets stuck after "D", with ID_FS_TYPE, ID_FS_UUID_ENC and ID_FS_LABEL_ENC being empty (a good reason to hang).
output:
Checking for USB_VOLUME_NAME...
A
B
/dev/sda1
C
/mnt/MYDRIVE
D
My dockerfile.template:
FROM balenalib/%%BALENA_MACHINE_NAME%%-node
# Enable udev for detection of dynamically plugged devices
ENV UDEV=on
COPY udev/usb.rules /etc/udev/rules.d/usb.rules
# Install dependencies
RUN install_packages util-linux
WORKDIR /usr/src/app
# Move scripts used for mounting USB
COPY scripts scripts
RUN chmod +x scripts/*
# server.js will run when container starts up on the device
CMD ["/bin/bash", "/usr/src/app/scripts/start.sh"]
start.sh:
echo "Mounting USB drive..."
cd /usr/src/app/scripts
/bin/bash mount.sh
# It won't get this far while the script above hangs.
echo "Starting server..."
cd /usr/src/app
/usr/local/bin/yarn run serve
I can confirm that everything works when running from within the container manually:
cd /usr/src/app/scripts
/bin/bash mount.sh
Output:
Checking for USB_VOLUME_NAME...
A
B
/dev/sda1
C
vfat
BE23-31BA
MYDRIVE
/mnt/MYDRIVE
D
E
F
(and the drive mounted)
How would I resolve the empty variables?
Always quote every shell variable you use. (Unless you're absolutely sure of what you're doing, and what you expect to happen if the variable value is empty or includes spaces.)
Without quoting, when you
/bin/grep -qw $ID_FS_TYPE /proc/filesystems
and $ID_FS_TYPE is empty, that word just gets omitted from the command line, so you get
/bin/grep -qw /proc/filesystems
which uses /proc/filesystems as a regexp, and tries to grep over its stdin; this leads to the apparent hang you see.
If instead you quote it:
/bin/grep -qw "$ID_FS_TYPE" /proc/filesystems
it will get an empty string as the regexp parameter and a filename as the input parameter, which will trivially succeed (but not hang).
For similar reasons, I'd expect you'd get a shell syntax error if $USB_VOLUME_NAME is unset, and the whole script will act oddly if that variable name has a space in it.

Check if two files are on the same volume in bash

Is there a way to check if two files are on the same volume in bash on Mac OS X?
Or, equivalently, to check if a given file is on the boot volume?
I've tried using ln and checking to see if it fails, but sometimes ln fails for reasons other than the cross-device link error.
I also tried using a function that prints the path of a file and then checking to see if that path contains /Volumes/ as a prefix, but not all of my remote volumes get mounted to /Volumes/.
Is there another way?
You are asking if two files are on the same filesystem. The canonical way of checking this is to call the stat() system call on the two files and check if they have the same st_dev value, where st_dev identifies the device on which the file resides.
You can use the stat command in bash to perform this test:
device=$(stat -f '%d' /path/to/file)
So, to check if two files are on the same filesystem:
dev1=$(stat -f '%d' /path/to/file1)
dev2=$(stat -f '%d' /path/to/file2)
if [ "$dev1" = "$dev2" ]; then
echo "file1 and file2 are on the same filesystem"
fi
The above works under OS X; the same check can be performed on Linux, but the stat command requires -c or --format instead of -f.
With df:
f1="$(df -P /path/to/file1.txt | awk 'NR!=1 {print $1}')"
f2="$(df -P /path/to/file2.txt | awk 'NR!=1 {print $1}')"
if [[ "$f1" = "$f2" ]]; then
echo "same filesystem"
else
echo "different filesystem"
fi

Bash: How to enforce output to one line?

I wrote the following Nagios check, which checks /etc/fstab for mounts and by using df checks if they are mounted properly:
#!/bin/bash
# Check mounts based on /etc/fstab
grep="/bin/grep"
awk="/bin/awk"
df="/bin/df"
mounts=$($grep nfs /etc/fstab | $awk '{print $2}')
# Check if mounts exist
for mount in $mounts; do
$df | $grep $mount &>/dev/null
if [ "$?" -eq "0" ]; then
msg="Mount $mount is mounted!"
else
msg="Mount $mount is not mounted!"
fi
echo $msg
done
When I run the check it returns a proper result:
[root#nyproxy5 ~]# ./check_mount.sh
Mount /proxy_logs is mounted!
Mount /proxy_dump is mounted!
Mount /sync_logs is mounted!
[root#nyproxy5 ~]#
But I want the output of the script to be 1 line rather than 3 lines, how can it be achieved?
I realize that the way the script is written at the moment doesn't allow it, even the "Mount X is mounted" message should be changed, but I'm having a hard time with the logic.
Thanks in advance
Change echo $msg to echo -n $msg
-n option will avoid printing newline
There is a general solution in case of some complicated command. Newlines or any other character could be removed this way:
./script.sh | tr -d '\n'
Or a win32 executable in cygwin:
./asd.exe | tr -d '\r\n'

How can I determine the volume name of CD/DVD in bash?

I'm trying to figure out how to get a bash script to automatically determine the path to a CD/DVD in order to process it. Running a Mac (10.7.4) the disk shows up at:
/Volumes/[Volume_name]
Since the volume name changes depending on the disk, I'm having to input that part manually. The operating system obviously knows it's a CD/DVD because of the way the controls work. Is it possible for bash to use whatever the OS uses to determine there is a CD/DVD and provide the path to it?
I use drutil.
drutil uses the DiscRecording framework to interact with attached burning devices.
#!/bin/bash
id=$(drutil status |grep -m1 -o '/dev/disk[0-9]*')
if [ -z "$id" ]; then
echo "No Media Inserted"
else
df | grep "$id" |grep -o /Volumes.*
fi
Given a UNIX block device name, diskutil info's output is easier to parse than mount's. For instance, this
function get_disk_mountpoint () {
diskutil info $1 | perl -ne 'print "$1\n" if /^ Mount Point: +(.*)/';
}
works. Trouble is, OS X also dynamically assigns /dev/disk? devices to removable media, so you still need something like
function get_optical_mountpoints () {
for i in $(diskutil list | egrep ^/); do
if diskutil info $i | egrep -q '^ Optical Drive Type:' ; then
get_disk_mountpoint $i
fi
done
}
to list the mount points for optical drives specifically.
If a disc is mounted you can use mount to view where it's mounted.
Putting together the pieces from above, I think this will do what you want:
get_cd_volume() {
local rc=1
for disk in $(diskutil list | grep ^/); do
if diskutil info "$disk" | grep -q Optical; then
df | sed -ne "s,^$disk.*\(/Volumes.*\)$,\1,p"
rc=0
fi
done
if (( rc )); then
echo >&2 "No volume mounted."
fi
return $rc
}

Resources