[SOLVED] Unable to edit fstab with sed to edit mount options
Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Unable to edit fstab with sed to edit mount options
Hi LQ,
This is my target file & it's contents..
Code:
vim /tmp/fstab_bk
# Commented Line followed by empty line
/dev/mapper/vg_root-lv_root / ext4 defaults 1 2
UUID=STRING1 /boot ext4 defaults 1 2
/dev/mapper/vg_root-lv_home /home ext4 defaults 1 2
/dev/mapper/vg_root-lv_opt /opt ext4 defaults 1 2
# Commented Line followed by empty line
/dev/mapper/vg_root-lv_tmp /tmp ext4 defaults,noexec 1 2
/dev/mapper/vg_root-lv_usr /usr ext4 defaults 1 2
/dev/mapper/vg_root-lv_var /var ext4 defaults 1 2
/dev/mapper/vg_root-lv_swap swap swap defaults 1 2
tmpfs /dev/shm tmpfs nodev,nosuid,noexec 0 0
devpts /dev/pts devpts STRING2 0 0
sysfs /sys sysfs defaults 1 2
proc /proc proc defaults 1 2
/tmp /var/tmp none bind,nodev,nosuid,noexec 0 0
/dest1 /MP1 ext4 defaults,nodev 1 2
/dest2 /MP2 ext3 defaults 1 2
# Commented Line followed by empty line
/dest3 /MP3 ext4 defaults 1 2
I am trying to write a script that would add 'nosuid' option for all non-root filesystems. So, my output file should be something like this -
Code:
# Commented Line followed by empty line
/dev/mapper/vg_root-lv_root / ext4 defaults 1 2
UUID=STRING1 /boot ext4 defaults 1 2
/dev/mapper/vg_root-lv_home /home ext4 defaults 1 2
/dev/mapper/vg_root-lv_opt /opt ext4 defaults 1 2
# Commented Line followed by empty line
/dev/mapper/vg_root-lv_tmp /tmp ext4 defaults,noexec 1 2
/dev/mapper/vg_root-lv_usr /usr ext4 defaults 1 2
/dev/mapper/vg_root-lv_var /var ext4 defaults 1 2
/dev/mapper/vg_root-lv_swap swap swap defaults 1 2
tmpfs /dev/shm tmpfs nodev,nosuid,noexec 0 0
devpts /dev/pts devpts STRING2 0 0
sysfs /sys sysfs defaults 1 2
proc /proc proc defaults 1 2
/tmp /var/tmp none bind,nodev,nosuid,noexec 0 0
/dest1 /MP1 ext4 defaults,nosuid,nodev 1 2
/dest2 /MP2 ext3 defaults,nosuid 1 2
# Commented Line followed by empty line
/dest3 /MP3 ext4 defaults,nosuid 1 2
I understand that I first need to discard all root and runtime directories (/proc, /dev/shm and such), so I can not do a blind sed string replacement on the file itself. Right now I can replace the string on the line output-
Code:
for i in $(cat /tmp/fstab_bk | grep -Ev "^$|^#|vg_root|UUID|nosuid|proc|sysfs|devpts"| awk '{print $1, $4}');do echo "string is $i";echo $i | sed 's/defaults/defaults,nosuid/' ; done
string is /dest1
/dest1
string is defaults,nodev
defaults,nosuid,nodev
string is /dest2
/dest2
string is defaults
defaults,nosuid
string is /dest3
/dest3
string is defaults
defaults,nosuid
This looks hopeful and my approach this problem is to match the $1 value with the first column of the file (so, matching /destN) and check if $4 contains the string "default" and replace it with "defaults,nosuid" for those lines only. For the life of me, I can't achieve this.
Here's what I am trying, but I am guessing there are syntax errors here -
Code:
]# for i in $(cat /tmp/fstab_bk | grep -Ev "^$|^#|vg_root|UUID|nosuid|proc|sysfs|devpts"| awk '{print $1}';
do
sed -i -e '/^$i / s/defaults/defaults,nosuid/' /tmp/fstab_bk
done
>
I am specifically looking for a one liner and since I am pretty mediocre in sed, a bit of explanation would be awesome too. Can I please get some pointers ? Also, it'd be interesting to show other approaches as well.
This is too complex for my poor brain, but this line:
Code:
sed -i -e '/^$i / s/defaults/defaults,nosuid/' /tmp/fstab_bk
will perform the substitution in lines that start with dollar-i. Since there are no such lines, it does nothing. If you want $i to be interpreted as a shell variable, use double quotes around the sed expression.
Since you use awk anyway, why not use it for the substitution as well? I don't know if awk has an option that is equivalent to sed's -i, but this is easily worked around.
You can discard unwanted lines by checking the second column (for root) or column 3:
Code:
$2=="/" || $3=="tmpfs" || $3=="devpts" || (...etc...) { next }
Then, in the remaining lines, add nosuid to the fourth columm:
Code:
{ $4 = $4 ",nosuid"; print }
That should be it, more or less. Not a one-liner, but perhaps easier to read than your construct.
Last edited by berndbausch; 02-28-2019 at 03:12 AM.
sed -i -e '/^$i / s/defaults/defaults,nosuid/' /tmp/fstab_bk
Quote:
will perform the substitution in lines that start with dollar-i. Since there are no such lines, it does nothing.
Sorry, could you please explain that ? Because $i is actually holding the value for first column of the fstab file.
Code:
# for i in $(cat /tmp/fstab_bk | grep -Ev "^$|^#|vg_root|UUID|nosuid|proc|sysfs|devpts"| awk '{print $1}');do echo "string is $i"; done
string is /dest1
string is /dest2
string is /dest3
I am trying to construct the awk script with your method and will post results.
awk ' /vg_root/ { continue }
/UUID/ { continue }
# all similar conditions comes here
{ $4=$4 ",nosuid"; print}'
but it is not tested, and probably I misunderstood something. (this is only a tip to see a different approach, because I did not really catch what do you need)
# awk ' /vg_root/ { continue }
/UUID/ { continue }
> /nosuid/ { continue }
> /"^$"/ { continue }
> { $4=$4 ",nosuid"; print}' /tmp/fstab_bk
awk: cmd. line:1: error: `continue' is not allowed outside a loop
awk: cmd. line:1: error: `continue' is not allowed outside a loop
If you can help with specifics, I have posted my original/target file and the intended result I am expecting. I am looking for a short one liner kind of thing and the fact that I came close at my first attempt with sed makes me hopeful that it's possible. I shall dig more on awk, but if I can get more pointers that'd be great.
# awk ' /vg_root/ { continue }
/UUID/ { continue }
> /nosuid/ { continue }
> /"^$"/ { continue }
> { $4=$4 ",nosuid"; print}' /tmp/fstab_bk
awk: cmd. line:1: error: `continue' is not allowed outside a loop
awk: cmd. line:1: error: `continue' is not allowed outside a loop
If you can help with specifics, I have posted my original/target file and the intended result I am expecting. I am looking for a short one liner kind of thing and the fact that I came close at my first attempt with sed makes me hopeful that it's possible. I shall dig more on awk, but if I can get more pointers that'd be great.
Yes, that was my mistake. It is next instead of continue. Sorry.
Also if you want to check empty lines you can write:
Code:
/^$/ { next } # << no " required
# or
length == 0 { next }
In sed you can do the same:
Code:
sed '/nosuid/n; /vg_root/n; /^$/n ..... s/defaults/defaults,nosuid/'
ok, i didn't read all of it, but allow me this one comment:
whenever i see a thread title "use sed to accomplish this-n-that"
my first thought is: "But is sed the right tool for the job?"
________________________
Quote:
Originally Posted by berndbausch
Use double quotes instead. In my mother tongue, Gänsefüßchen (much cuter, I think). Try this:
Code:
i=123
echo ‘$i’
echo “$i”
Gänsefüßchen!
but something's off with your formatting.
consider this:
ok, i didn't read all of it, but allow me this one comment:
whenever i see a thread title "use sed to accomplish this-n-that"
my first thought is: "But is sed the right tool for the job?"
________________________
Gänsefüßchen!
but something's off with your formatting.
consider this:
Code:
i=123
echo ‘$i’
echo '$i'
echo “$i”
echo "$i"
That's probably Windows and/or Firefox mangling my Gänsefüßchen.
Bold lines are somehow not matching my expected results, whereas the blue lines are expected.
[The dot (.) in the replacement string was a typo, but I left it as it is, since it's all being done on a test file ]
Here is one more attempt, different regex ..
Code:
# sed '/nosuid/n; /vg_root/n; /^$/n; /^#/n; /UUID/n; /sysfs/n; /proc/n; /tmp/n; /devpts/n; s/defaults/defaults.nosuid/' /tmp/fstab_bk
# Commented Line followed by empty line
/dev/mapper/vg_root-lv_root / ext4 defaults.nosuid 1 2
UUID=STRING1 /boot ext4 defaults 1 2
/dev/mapper/vg_root-lv_home /home ext4 defaults.nosuid 1 2
/dev/mapper/vg_root-lv_opt /opt ext4 defaults 1 2
# Commented Line followed by empty line
/dev/mapper/vg_root-lv_tmp /tmp ext4 defaults,noexec 1 2
/dev/mapper/vg_root-lv_usr /usr ext4 defaults.nosuid 1 2
/dev/mapper/vg_root-lv_var /var ext4 defaults 1 2
/dev/mapper/vg_root-lv_swap swap swap defaults.nosuid 1 2
tmpfs /dev/shm tmpfs nodev,nosuid,noexec 0 0
devpts /dev/pts devpts STRING2 0 0
sysfs /sys sysfs defaults.nosuid 1 2
proc /proc proc defaults 1 2
/tmp /var/tmp none bind,nodev,nosuid,noexec 0 0
/dest1 /MP1 ext4 defaults.nosuid,nodev 1 2
/dest2 /MP2 ext3 defaults.nosuid 1 2
# Commented Line followed by empty line
/dest3 /MP3 ext4 defaults.nosuid 1 2
sorry, I'm trying to understand. * in those regexps are not ok. Also the dot in defaults.nosuid looks strange.
For me it looks like that sed works properly, just the expression is not the one you really need.
The logic is to "skip" all the lines which should not be changed:
Code:
/sysfs/n;
and finally substitute defaults. I was thinking about replacing n to {p;d}, that will lead to something like this:
Code:
sed '/UUID/{p;d};/^#/{p;d};/^$/{p;d};/sysfs/{p;d};/proc/{p;d};/tmpfs/{p;d};/devpts/{p;d};s/defaults/defaults,nosuid/'
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.