7

I encountered the following issue with parameter expansion while trying to write a script for setting the metric of my VPN's default route.

For testing purposes, I've simplified the code to the following:

vpn_route='default via 10.106.160.1 proto static metric 50'

echo ip route del "$vpn_route"
echo ip route add "${vpn_route/metric +([0-9])/metric 101}"
echo ip route add "${vpn_route/%metric */metric 101}"

Once I remove the echo commands, this should

  1. delete the existing default route
  2. Create a new route with the metric <number> part replaced by metric 101

For testing, I added a second variant with a less specific pattern.

If I execute this code in an interactive bash shell, it works as expected:

$ vpn_route='default via 10.106.160.1 proto static metric 50'
$ echo ip route del "$vpn_route"
ip route del default via 10.106.160.1 proto static metric 50
$ echo ip route add "${vpn_route/metric +([0-9])/metric 101}"
ip route add default via 10.106.160.1 proto static metric 101
$ echo ip route add "${vpn_route/%metric */metric 101}"
ip route add default via 10.106.160.1 proto static metric 101

However, if I execute the script, I get the following:

$ cat lower-vpn-priority.sh
#!/usr/bin/env bash

vpn_route='default via 10.106.160.1 proto static metric 50'

echo ip route del "$vpn_route"
echo ip route add "${vpn_route/metric +([0-9])/metric 101}"
echo ip route add "${vpn_route/%metric */metric 101}"

$ bash lower-vpn-priority.sh
ip route del default via 10.106.160.1 proto static metric 50
ip route add default via 10.106.160.1 proto static metric 50
ip route add default via 10.106.160.1 proto static metric 101

Can anyone explain to me what's going on here? :)

0
12

You need to enable extended globs for +([0-9]) to work. It's probably set in your bashrc, so is enabled in the interactive shell, but not in the script. Add shopt -s extglob to the script to enable it. See Pattern Matching in the manual. Without it, the pattern doesn't match, and ${var/pattern/replacement} leaves the value as-is.

4
  • 3
    You might want to add that the reason it works at the prompt of an interactive shell is because that shopt -s extglob must be somewhere in ~/.bashrc or the equivalent system-wide file in /etc or possibly one of the files sourced from there. For instance, I believe the third party bash-completion project enables extglob. – Stéphane Chazelas Jan 11 at 13:13
  • @StéphaneChazelas, yep. – ilkkachu Jan 11 at 13:14
  • Ah, that's it - I was looking for shell options/flags that might differ, but couldn't find them. Thank you! – theCalcaholic Jan 13 at 10:29
  • 1
    @theCalcaholic, the command line option is -O extglob. The shopt options are nonstandard extensions, and IIRC shopt itself is Bash-specific. (Zsh has setopt for a similar purpose.) Note that you can't use -O extglob on the hashbang line, it won't work on Linux because it needs to be two distinct arguments. – ilkkachu Jan 13 at 12:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.