Sh vs ./

Hi guys,

I have a small script which reads my IP address from an URL and then sets it :

#!/bin/bash
MAC_ADDR=$(ifconfig eth0 | sed -n 's/.*HWaddr \([a-f0-9:]*\).*/\1/p')
IP=($(curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s))
for ip in ${IP[@]:1}; do
echo "Adding IP: $ip"
    ip addr add dev eth0 $ip/24
done

I saved it in a file script.sh with exec rights. Now I am trying to put it under /etc/rc.local to run at startup.

My rc.local looks like :

root@ip-10-0-0-184:~# cat /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
sh /root/script.sh
exit 0

When I run it via ./script.sh all works fine. When I try to run it via sh I get the following

/root/script.sh: 3: /root/script.sh: Syntax error: "(" unexpected

Do you have any insights on how can I fix that ?

That error comes from using a bourne shell - are you on Solaris, or more correctly what shell does /bin/sh invoke?

Please show the output of:

ls -l /bin/sh
uname -a
lrwxrwxrwx 1 root root 4 Mar 29  2012 /bin/sh -> dash

Linux ip-10-37-161-45 3.2.0-40-virtual #64-Ubuntu SMP Mon Mar 25 21:42:18 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

FWIW - https://bugs.launchpad.net/ubuntu/\+source/dash/\+bug/141481

dash is supposed to be POSIX-compliant but it still seems that it does not have all of the features that bash has, the $( ) construct is an example. You need to use backticks

Example:

`my command`
# instead of
$( my command)

PS: I don't use dash, but you should be aware of the gotchas if you choose to keep using it. dash is not meant as a one-to-one replacement for bash.

1 Like

Thanks, it was really helpful.
I guess cd /root && ./script.sh will also right straight from rc.local ...right ?

According to its documentation, dash does support the modern, POSIX-compliant $(...) command substitution syntax.

I don't use dash either, but I suspect the problem lies with the parentheses surrounding the command substitution, which look like a bash list/array assignment.

Regards,
Alister

What would be the fastest way to sort this out ?
Tried actually the following :

#!/bin/bash MAC_ADDR=`ifconfig eth0 | sed -n 's/.*HWaddr \([a-f0-9:]*\).*/\1/p'` IP=`(curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s)` for ip in ${IP[@]:1}; do echo "Adding IP: $ip"     ip addr add dev eth0 $ip/24 done 

But still getting an error..

If it works with bash, then just use bash.

The errors are the result of running a script which depends on arrays and array operations on a shell which does not support arrays. dash aims to be a nimble shell which does not support much beyond the POSIX standard. sh arrays are not part of POSIX.

If you need to port it to sh/dash, then you must abandon the arrays and utilize a different approach, e.g. pipe curl's output into a while-loop.

Also, please, don't be vague when reporting errors. Instead of "still getting an error", post the exact error message.

Regards,
Alister

Try replacing

IP=($(curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s))

with

IP=$(curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s)