Home > Software design >  Replace part of pattern space with result of bash function
Replace part of pattern space with result of bash function

Time:04-16

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.

CodePudding user response:

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
  • Related