0

I'm trying to create a script that automatically looks for plugged in devices and makes a compressed backup of it. However, I'm having trouble finding the correct way on how to use expr:

#!/bin/bash

MountText=`mount`
# Show result of regex search
expr "$MountText" : '\/dev\/(sd[^a])\d on [\S]+\/[\s\S]+? type'

The expression by itself is \/dev\/(sd[^a])\d on [\S]+\/[\s\S]+? type, and captures the device name (sd*), while excluding mounts relating to sda.

I drafted the regex on Regexr (regex shared in link), and used what mount dumped (gist).

For some reason, it only gives this odd error:

0

I looked around, and I found this SO question. It didn't help me too much, because now it's implying that expr didn't recognize the parentheses I used to capture the device, and it also believed that the expression didn't capture anything!

I'm really confused. What am I doing wrong?

Community
  • 1
  • 1
Nolan Akash
  • 989
  • 8
  • 21
  • 1
    Regular expressions only work within languages, shells use wildcards or globs, please google these terms for the shell you are using, **echo $SHELL ** – Arif Burhan Mar 02 '16 at 00:59
  • Thanks, didn't hear any information that `expr` uses globs. Though, I don't get what you mean by **echo $SHELL**, because I mentioned both in tags and in the hashbang that I'm using bash. – Nolan Akash Mar 02 '16 at 01:05
  • @ArifBurhan Also, I checked the `man` pages, and it says that the phrase `expr STRING : REGEXP` uses regular expressions. – Nolan Akash Mar 02 '16 at 01:14
  • `echo $(...)` is almost always redundant; there's no reason to capture the output of a command just to output it. – chepner Mar 02 '16 at 02:19
  • @chepner I commented that I wanted to see what It would produce. If I immediately put it into a script, it might have dangerous consequences. – Nolan Akash Mar 02 '16 at 02:22
  • No, it would have exactly the same effect: its output would go to standard output. – chepner Mar 02 '16 at 02:37
  • @chepner Oh... right... – Nolan Akash Mar 02 '16 at 02:48
  • The 0, by the way, is just the count of matching characters. (The errors noted in my answer cause your regular expression to not have a capture group and not match the given text.) – chepner Mar 02 '16 at 02:51

1 Answers1

1

A few things to note with expr:

  1. The regular expression is implicitly anchored at the beginning of the string (as if you started the expression with ^).
  2. The capture group is indicated with escaped parentheses, \(...\).
  3. Only basic regular expressions are supported. Specifically, \s, \S, and +? are not supported.

The following will match the one device.

expr "$MountText" : '.*/dev/\(sd[^a]\)[[:digit:]] on '

Note that you don't need to use expr with bash, which has regular-expression matching built in.

regex='/dev/(sd[^a])[[:digit:]] on '
mount | while IFS= read -r line; do
    [[ $line =~ $regex ]] && echo ${BASH_REMATCH[1]}
done
chepner
  • 497,756
  • 71
  • 530
  • 681
  • This gives the same error as before, so while some of this might help me, it still doesn't work. Did you test it out with the gist I had? – Nolan Akash Mar 02 '16 at 02:27
  • Sorry, tried to do too much from memory. Updating, but there is one caveat: you can only capture the first device that matches, not any more. (The non-greedy `+?` operator isn't supported, but would be unnecessary anyway.) – chepner Mar 02 '16 at 02:34
  • This works! I don't believe I will need to find other devices, but if I need to, I think I can use string manipulation to remove the captured line. Thanks so much! – Nolan Akash Mar 02 '16 at 02:54