how to do this in bash script - linux

in Linux, suppose mount command return this
/dev/sdc1 on /media/ELF (^-^)V type vfat
/dev/sdb1 on /media/PENDRIVE type vfat
all I want to do is get all mount point of my usb disk.
I did that already, using combination of grep and sed I can get these:
/media/ELF (^-^)V
/media/PENDRIVE
the problem is, when I do for loop in bash, those text will become 3 part instead of 2 parts , I mean :
suppose I put the result of those text in LIST
for list in $LIST; do
echo $list
done;
the result of that for loop becomes
/media/ELF
(^-^)V
/media/PENDRIVE
how to handle this issue? or are there any easier ways to get mount point of my usb disk?
Thanks

If you've already extracted the mountpoint paths and the only issue is to process them in a loop:
while read -r mountpoint; do
echo "[$mountpoint]"
done < <(mount | grep /media | grep uhelper=udisks | sed -e 's/\/dev\/.*on //g' -e 's/ type .*//g')

Related

cat: pid.txt: No such file or directory

I have a problem with cat. I want to write script doing the same thing as ps -e. In pid.txt i have PID of running processes.
ls /proc/ | grep -o "[0-9]" | sort -h > pid.txt
Then i want use $line like a part of path to cmdline for evry PID.
cat pid.txt | while read line; do cat /proc/$line/cmdline; done
i try for loop too
for id in 'ls /proc/ | grep -o "[0-9]\+" | sort -h'; do
cat /proc/$id/cmdline;
done
Don't know what i'm doing wrong. Thanks in advance.
I think what you're after is this - there were a few flaws with all of your approaches (or did you really just want to look at process with a single-digit PID?):
for pid in $(ls /proc/ | grep -E '^[0-9]+$'|sort -h); do cat /proc/${pid}/cmdline; tr '\x00' '\n'; done
You seem to be in a different current directory when running cat pid.txt... command compared to when you ran your ls... command. Run both your commands on the same terminal window, or use absolute path, like /path/to/pid.txt
Other than your error, you might wanna remove -o from your grep command as it gives you 1 digit for a matching pid. For example, you get 2 when pid is 423. #Roadowl also pointed that already.

How to extract the first column from an output line?

When executing
sudo fdisk -l | tail -n 1
the result gives me
/dev/sdb1 * 8064 7669823 3830880 b W95 FAT32
So what I need is to extract just "/dev/sdb1/".
Not exactly just sdb1, whatever device that is listed last. What if I have two flash drives and I need the last one?
I've searching everywhere and I couldn't find how.
Thanks in advance.
sudo fdisk -l | tail -n 1 | awk '{print $1}'
will produce as
/dev/sdb1

compare mount and /etc/filesystems in AIX

I want to compare the output put of mount command to the /etc/filesystems. Basically we want to validate everything is getting mounted properly as defined in /etc/filesystems after any system change(reboot etc.)
My basic script is:
#!/bin/bash
mountpoint="/vol/test/abc"
if grep -qs "$mountpoint" /etc/filesystems; then
echo "good"
else
echo "bad"
fi
Is this right approach? Please suggest. Also How can I get all the volumes that are being returned by executing mount command?
I think the general approach you want is to first generate a list of all the filesystems that you expect to be mounted, by looking at /etc/filesystems (use some combination of awk, grep, etc. to get just the names).
Then, get the list of filesystems that are actually mounted by running the mount command with no arguments.
Finally, compare the original list with the second list, and make sure nothing is missing.
As z242 suggested:
# Matching lines from /etc/filesystems
sed -n 's%^\(/.*\):%\1%p' /etc/filesystems | sort -o f1
# Matching lines from mount command
mount | tail +3 | awk '{print $2}' | sort -o f2
# Now compare the two
comm -3 f1 f2
Items listed with no indent are those in /etc/filesystems but not mounted. Items listed with an indent are those mounted but not in /etc/filesystems. If you don't care about the latter change comm -3 to comm -23

How to find the directory a device is mounted to?

In Linux, is it possible via a bash script to take '/dev/sr0' and determine what folder it's mounted to and perform extra actions on said folder?
You can output the directory name via this command:
grep /dev/sr0 /etc/mtab | cut "-d " -f2
or use it in other commands like this (e.g. list its contents):
ls $(grep /dev/sr0 /etc/mtab | cut "-d " -f2)
You can use the command mount(8) to find what device is mounted where. On Linux this information is found in the /proc/mounts file.

Give the mount point of a path

The following, very non-robust shell code will give the mount point of $path:
(for i in $(df|cut -c 63-99); do case $path in $i*) echo $i;; esac; done) | tail -n 1
Is there a better way to do this in shell?
Postscript
This script is really awful, but has the redeeming quality that it Works On My Systems. Note that several mount points may be prefixes of $path.
Examples
On a Linux system:
cas#txtproof:~$ path=/sys/block/hda1
cas#txtproof:~$ for i in $(df -a|cut -c 57-99); do case $path in $i*) echo $i;; esac; done| tail -1
/sys
On a Mac OSX system
cas local$ path=/dev/fd/0
cas local$ for i in $(df -a|cut -c 63-99); do case $path in $i*) echo $i;; esac; done| tail -1
/dev
Note the need to vary cut's parameters, because of the way df's output differs; using awk solves this, but even awk is non-portable, given the range of result formatting various implementations of df return.
Answer
It looks like munging tabular output is the only way within the shell, but
df -P "$path" | tail -1 | awk '{ print $NF}'
based on ghostdog74's answer, is a big improvement on what I had. Note two new issues: firstly, df $path insists that $path names an existing file, the script I had above doesn't care; secondly, there are no worries about dereferencing symlinks. This doesn't work if you have mount points with spaces in them, which occurs if one has removable media with spaces in their volume names.
It's not difficult to write Python code to do the job properly.
df takes the path as parameter, so something like this should be fairly robust;
df "$path" | tail -1 | awk '{ print $6 }'
In theory stat will tell you the device the file is on, and there should be some way of mapping the device to a mount point.
For example, on linux, this should work:
stat -c '%m' $path
Always been a fan of using formatting options of a program, as it can be more robust than manipulating output (eg if the mount point has spaces). GNU df allows the following:
df --output=target "$path" | tail -1
Unfortunately there is no option I can see to prevent the printing of a header, so the tail is still required.
i don't know what your desired output is, therefore this is a guess
#!/bin/bash
path=/home
df | awk -v path="$path" 'NR>1 && $NF~path{
print $NF
}'
Using cut with -c is not really reliable, since the output of df will be different , say a 5% can change to 10% and you will miss some characters. Since the mount point is always at the back, you can use fields and field delimiters. In the above, $NF is the last column which is the mount point.
I would take the source code to df and find out what it does besides calling stat as Douglas Leeder suggests.
Line-by-line parsing of the df output will cause problems as those lines often look like
/dev/mapper/VOLGROUP00-logical--volume
1234567 1000000 200000 90% /path/to/mountpoint
With the added complexity of parsing those kinds of lines as well, probably calling stat and finding the mountpoint is less complex.
If you want to use only df and awk to find the filesystem device/remote share or a mount point and they include spaces you can cheat by defining the field separator of awk to be a regular expression that matches the format of the numeric sizes used to display total size, used space, available space and capacity percentage. By defining those columns as the field separator you are then left with $1 representing the filesystem device/remote share and $NF representing the mount path.
Take this for example:
[root#testsystem ~] df -P
Filesystem 1024-blocks Used Available Capacity Mounted on
192.168.0.200:/NFS WITH SPACES 11695881728 11186577920 509303808 96% /mnt/MOUNT WITH SPACES
If you attempt to parse this with the quick and dirty awk '{print $1}' or awk '{print $NF}' you'll only get a portion of the filesystem/remote share path and mount path and that's no good. Now make awk use the four numeric data columns as the field separator.
[root#testsystem ~] df -P "/mnt/MOUNT WITH SPACES/path/to/file/filename.txt" | \
awk 'BEGIN {FS="[ ]*[0-9]+%?[ ]+"}; NR==2 {print $1}'
192.168.0.200:/NFS WITH SPACES
[root#testsystem ~] df -P "/mnt/MOUNT WITH SPACES/path/to/file/filename.txt" | \
awk 'BEGIN {FS="[ ]*[0-9]+%?[ ]+"}; NR==2 {print $NF}'
/mnt/MOUNT WITH SPACES
Enjoy :-)
Edit: These commands are based on RHEL/CentOS/Fedora but should work on just about any distribution.
Just had the same problem. If some mount point (or the mounted device) is sufficent as in my case You can do:
DEVNO=$(stat -c '%d' /srv/sftp/testconsumer)
MP=$(findmnt -n -f -o TARGET /dev/block/$((DEVNO/2**8)):$((DEVNO&2**8-1)))
(or split the hex DEVNO %D with /dev/block/$((0x${DEVNO:0:${#DEVNO}-2})):$((0x${DEVNO:2:2})))
Alternatively the following loop come in to my mind, out of ideas why I cannot find proper basic command..
TARGETPATH="/srv/sftp/testconsumer"
TARGETPATHTMP=$(readlink -m "$TARGETPATH")
[[ ! -d "$TARGETPATHTMP" ]] && TARGETPATHTMP=$(dirname "$TARGETPATH")
TARGETMOUNT=$(findmnt -d backward -f -n -o TARGET --target "$TARGETPATHTMP")
while [[ -z "$TARGETMOUNT" ]]
do
TARGETPATHTMP=$(dirname "$TARGETPATHTMP")
echo "$TARGETPATHTMP"
TARGETMOUNT=$(findmnt -d backward -f -n -o TARGET --target "$TARGETPATHTMP")
done
This should work always but is much more then I expect for such simple task?
(Edited to use readlink -f to allow for non existing files, -m or -e for readlink could be used instead if more components might not exists or all components must exists.)
mount | grep "^$path" | awk '{print $3}'
I missed this when I looked over prior questions: Python: Get Mount Point on Windows or Linux, which says that os.path.ismount(path) tells if path is a mount point.
My preference is for a shell solution, but this looks pretty simple.
I use this:
df -h $path | cut -f 1 -d " " | tail -1
Linux has this, which will avoid problem with spaces:
lsblk -no MOUNTPOINT ${device}
Not sure about BSD land.
f () { echo $6; }; f $(df -P "$path" | tail -n 1)

Resources