Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed returning different result on different platforms

Hi using following command on an x86 machine (using /bin/sh) returns: <port>3<port>

test="port 3"
echo $test | sed -r 's/\s*port\s*([0-9]+)\s*/<port>\1<\/port>/'

but running same command on sh shell of an ARM based network switch returns the string port 3.

How can I get same result on switch as I got on my x86 machine? To me it seems like digit is not being captured by [0-9].

like image 538
Usman Avatar asked May 02 '12 16:05

Usman


2 Answers

\s is a GNU sed extension to the standard sed behavior. GNU sed is the implementation on desktop/server Linux systems. Most embedded Linux systems run BusyBox, a suite of utilities with a markedly smaller footprint and fewer features.

A standard way of specifying “any space character” is the [:space:] character class. It is supported by BusyBox (at least, by most BusyBox installations; most BusyBox features can be stripped off for an even lower footprint).

BusyBox also doesn't support the -r option, you need to use a basic regular expression. In a BRE, \(…\) marks groups, and there is no + operator, only *.

echo "$test" | sed 's/[[:space:]]*port[[:space:]]*\([0-9][0-9]*\)[[:space:]]*/<port>\1<\/port>/'

Note that since you didn't put any quotes around $test, the shell performed word splitting and wildcard expansion on the value of the variable. That is, the value of the variable was treated as a whitespace-separated list of file names which were then joined by a single space. So if you leave out the quotes, you don't have to worry about different kinds of whitespace, you can write echo $test | sed 's/ *port *([0-9][0-9]*) */<port>\1<\/port>/'. However, if $test had been port *, the result would have depended on what files exist in the current directory.

like image 147
Gilles 'SO- stop being evil' Avatar answered Sep 28 '22 10:09

Gilles 'SO- stop being evil'


Not all seds support reg-expression short-hand like \s. A more portable version is

  test="port 3"
  echo "$test" | sed -r 's/[ ]*port[ ]*([0-9]+)[ ]*/<port>\1<\/port>/'

If you really need to check for tab chars as well, just add them to the char class (in all 3 places) that, in my example just contain space chars, i.e. the [ ] bit.

output

<port>3</port>

I hope this helps.

like image 38
shellter Avatar answered Sep 28 '22 11:09

shellter