0

I read that mounting devices by name (/dev/sdxy) was not-so-safe because the names of the devices might change between reboots. So, I want to generate an fstab file with UUIDs in place of device names. Tutorials on the internet suggest I find the UUID of the devices I want and manually copy-paste them in /etc/fstab.

I think there has to be a way to automate that and I'm trying to get sed to work from within a script. Here is the closest I could get to a working script :

#!/bin/bash

function GetUUID()
{
    # Arg 1 is expected to be a device (such as /dev/sdc1)
    # This function calls blkid on the device and prints to stdout UUID=[uuid], without quotes, so that it can be passed out to SED.
    echo -n calling GetUUID on $1
    FullString=$(blkid $1 | tr -d '"')
    UUID=$(echo ${FullString} | cut -d ' ' -f2)
    echo $UUID
}

# Greps /etc/mtab and looks for user given disk (say, /dev/sdc)
# Changes the names of all mounted partitions of that disk (eg all /dev/sdcx) to their UUIDs, in compatible format with /etc/fstab
# Outputs results to stdout

if [[ $# -eq 0 ]]
then
    # If no argument, I will not try to guess a default, that looks dangerous.
    echo "Usage : RobustMtabCopy /dev/somedisk (will search mstab for all /dev/somediskX and replace the names by their UUIDS)"
    exit 22
else
    # Else, look for anything like /dev/somediskX, source the function that will make the output pretty, get the pretty form of UUID, and put it in place of the device name in the output.
    grep $1 /etc/mtab | sed -E "s|(${1}[[:digit:]])|$(GetUUID \1)|g"
fi

The expected output would be something like this :

UUID=SOME-UUID mount-point fs options 0 0
UUID=SOME-OTHER-UUID mount-point fs options 0 0

The actual output :

./script.sh /dev/sdc
  mount-point fs options 0 0
  mount-point fs options 0 0

A little debugging shows that I call the GetUUID with parameter "1" (so blkid outputs empty string). Escaping that \ did not help.

There are a couple excellent suggestions that do not quite do what I want :

  • I am having trouble with how-to-replace-a-value-with-the-output-of-a-command-in-a-text-file because the function I call uses the pattern I matched in sed, and I can't figure out how to pass that to my command ;
  • I read something on stackoverflow about using the "e" flag to call shell commands from within sed ; it doesn't quite work for me because the whole pattern is replaced and I'd like to replace only the match (I can't put my hand on the reference though).

Any help would be greatly appreciated.

Betebizarre
  • 128
  • 5
  • If you use GNU sed have a look at the `e` modifier of the substitute command. It executes the result of a substitution as a shell command and uses the result as replacement string. – Renaud Pacalet Apr 15 '22 at 13:38
  • @RenaudPacalet Thank you for reading me. I looked into it, but instead of replacing just the match (/dev/sdcX in my example) it replaces the whole line, including the trailing information about the filesystem and such. I'm not sure how to recover the information afterwards. – Betebizarre Apr 15 '22 at 13:48
  • See my answer for a possible use of the `e` modifier. And please edit your question to show an example content of `/etc/mtab` corresponding to your expected output. It is missing. – Renaud Pacalet Apr 15 '22 at 14:52

1 Answers1

0

With GNU sed for the e modifier of the substitute command:

grep "$1" /etc/mtab |
sed -E 's|(.*)('"$1"')(.*)|printf "UUID=%s %s%s\\n" "$(blkid -s UUID -o value "\2")"  "\1" "\3"|e'

But beware: you will have to pass a regular expression that matches exactly the full device names, no more no less. Example:

$ ./script.sh '/dev/sdc[0-9]*'
UUID=4071fbd0-711a-477d-877a-ee4b6be261fc  /tmp ext4 rw,relatime 0 0
UUID=a34227b0-bb5e-44fb-9207-dc48cf4be022  /home ext4 rw,relatime 0 0
UUID=bcfa9073-79ad-43ca-ba34-ceb8aecb23bf  /var ext4 rw,relatime 0 0

If, like in your example, you know already the kind of devices you have (/dev/sd[a-z][0-9]+) and want to pass only the leading stem you can adapt the sed script:

grep "$1" /etc/mtab |
sed -E 's|(.*)('"$1"'\S+)(.*)|printf "UUID=%s %s%s\\n" "$(blkid -s UUID -o value "\2")"  "\1" "\3"|e'

And then:

$ ./script.sh '/dev/sdc'
UUID=4071fbd0-711a-477d-877a-ee4b6be261fc  /tmp ext4 rw,relatime 0 0
UUID=a34227b0-bb5e-44fb-9207-dc48cf4be022  /home ext4 rw,relatime 0 0
UUID=bcfa9073-79ad-43ca-ba34-ceb8aecb23bf  /var ext4 rw,relatime 0 0
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • Thank you very much for your time. The script you gave solves my problem perfectly. I have to say it looks a bit like black magic. In particular I thought you couldn't expand variables between simple quotes, which seems bypassed here by closing and reopening them around some variables. Do you have a pointer to somewhere that would explain that ? – Betebizarre Apr 15 '22 at 15:19
  • I do not have a pointer in mind but this black magic is quite simple: strings concatenation. Some strings are single-quoted and don't undergo parameter expansion, some are double-quoted and undergo parameter expansion. So, if the value of variable `foo` is `bar`, `'$foo'"$foo"'$foo'` expands as `$foobar$foo`. Simple. – Renaud Pacalet Apr 15 '22 at 16:58