0

I need to do a string manipuilation in shell script (/bin/dash):

#!/bin/sh

PORT="-p7777"
echo $PORT
echo ${PORT/p/P}

the last echo fails with Bad substitution. When I change shell to bash, it works:

#!/bin/bash

PORT="-p7777"
echo $PORT
echo ${PORT/p/P}

How can I implement the string substitution in dash ?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
Martin Vegter
  • 136
  • 9
  • 32
  • 56
  • FYI... I believe the proper way to switch to Bash is `#!/usr/bin/env bash`. It will work on some of the BSD's, where Bash is an add-on and installed in `/usr/local`. Confer, [Why is it better to use “#!/usr/bin/env NAME” instead of “#!/path/to/NAME” as my shebang?](https://unix.stackexchange.com/q/29608/56041) – jww Dec 08 '18 at 07:33
  • @jww - I don't want to switch to bash. I need to implement this in `dash` – Martin Vegter Dec 08 '18 at 07:34
  • 1
    You can use `echo $PORT | tr 'p' 'P'` to *translate* lower-p to upper-P which will not depend on the shell. You can use `tr [:lower:] [:upper:]` to translate ALL lower-case characters to upper-case. – David C. Rankin Dec 08 '18 at 07:34
  • 1
    @MartinVegter - You provided code that switched to the Bash shell. – jww Dec 08 '18 at 07:35
  • `#!/usr/bin/env` *increases* the chance of find *an* interpreter, but the correct thing to do is adjust the path to the specific path that locates the correct interpreter on *your* machine. Shebangs were never intended to address portability. – chepner Dec 08 '18 at 13:30
  • A nice page explaining how to make your script POSIX compliant, is [here](https://wiki.ubuntu.com/DashAsBinSh). – kvantour Dec 08 '18 at 13:47

2 Answers2

4

The substitution you're using is not a basic POSIX feature (see here, in section 2.6.2 Parameter Expansion), and dash doesn't implement it.

But you can do it with any of a number of external helpers; here's an example using sed:

PORT="-p7777"
CAPITOLPORT=$(printf '%s\n' "$PORT" | sed 's/p/P/')
printf '%s\n' "$CAPITOLPORT"

BTW, note that I'm using printf '%s\n' instead of echo -- that's because some implementations of echo do unpredictable things when their first argument starts with "-". printf is a little more complicated to use (you need a format string, in this case %s\n) but much more reliable. I'm also double-quoting all variable references ("$PORT" instead of just $PORT), to prevent unexpected parsing.

I'd also recommend switching to lower- or mixed-case variables. There are a large number of all-caps variable that have special meanings, and if you accidentally use one of those it can cause problems.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • You don't need a command substitution; just strip the `-p` and append the result to `-P`: `CAPITOLPORT="-P${PORT#-p}"` – chepner Dec 08 '18 at 13:18
  • @chepner - that is not a good solution. This will put `-P` infront, whether or not the string contains `-p`. That is not what I need. The string can be empty, in which case nothing should be changed. – Martin Vegter Dec 08 '18 at 14:04
  • You never mentioned that until now.You can check if the string is nonempty and starts with `-p` with `if [ -n "$PORT" ] && [ "$PORT" != "${PORT#-p}" ]; then PORT="-P${PORT#-p}"`. Or is `PORT` an arbitrary string that might match `-p[0-9]*` *somewhere* in the middle? – chepner Dec 08 '18 at 15:30
  • @chepner - I mentioned that I am looking for equivalent of bashes `${PORT/p/P}` which works in dash. – Martin Vegter Dec 08 '18 at 17:20
  • And I'm saying you probably don't *need* the exact equivalent, if it handles cases that can never arrive in practice. – chepner Dec 08 '18 at 17:21
  • @chepner - your non-empty checking construct looks overcomplicated. More so, when the parameter expansion `${PORT:+-P${PORT#-p}}` as suggested by @James Brown works great – Martin Vegter Dec 08 '18 at 17:23
3

Using parameter expansion:

$ cat foo.sh
#!/bin/sh

PORT="-p7777"
echo $PORT
echo ${PORT:+-P${PORT#-p}}

PORT=""
echo $PORT
echo ${PORT:+-P${PORT#-p}}

Run it:

$ /bin/sh foo.sh
-p7777
-P7777

Update:

$ man dash:
- - 
${parameter#word}     Remove Smallest Prefix Pattern.

$ echo ${PORT#-p}
7777

$ man dash
- - 
${parameter:+word}    Use Alternative Value.

$ echo ${PORT:+-P${PORT#-p}}
-P7777
James Brown
  • 36,089
  • 7
  • 43
  • 59