2

The examples have been run on a Raspberry Pi 3 running the 2017-04-10 version of Raspbian Jessie updated to early June 2017. Bash is at version 4.3.30(1).

While experimenting with some code recently, I found that the contents of a bash array were being executed. Fortunately they were not dangerous!

Here's a simple function:

#!/bin/bash
echo "y.sh starting"
echo "parameter string is <$@>"
args=( $@ )
echo "args array is <${args[@]}>"
echo "args array length is ${#args[@]}"
echo "y.sh ending"

and here is the output

pi@brassica:~ $ ./y.sh
y.sh starting
parameter string is <>
args array is <>
args array length is 0
y.sh ending
pi@brassica:~ $ ./y.sh ls
y.sh starting
parameter string is <ls>
args array is <ls>
args array length is 1
y.sh ending

Nothing unexpected above here.

After adding the y* parameter, the ls command output appears in the array:

pi@brassica:~ $ ./y.sh ls y*
y.sh starting
parameter string is <ls y01.sh y02.sh y03.sh y04a.sh y04.sh y.sh ytq>
args array is <ls y01.sh y02.sh y03.sh y04a.sh y04.sh y.sh ytq>
args array length is 8
y.sh ending

but when -la is added, there's no sign of the extra information

pi@brassica:~ $ ./y.sh ls -la y*
y.sh starting
parameter string is <ls -la y01.sh y02.sh y03.sh y04a.sh y04.sh y.sh ytq>
args array is <ls -la y01.sh y02.sh y03.sh y04a.sh y04.sh y.sh ytq>
args array length is 9
y.sh ending

It would be very helpful if someone could explain both why the command is being executed and what changes can be made so that it won't be executed. An explanation of why the "long" output from ls is not produced would also be of interest.

With thanks from the home of the Cheshire Cat.

user8150417
  • 61
  • 1
  • 6

1 Answers1

6

You are not executing ls -la y* you're passing arguments to y.sh. The first is ls, then -la then all of the files that the glob y* expands to each becomes its own parameter.

So you are not executing the command, but the glob is being expanded by the shell.

That's what happens when you run ls y* too. You aren't actually passing the string y* to ls. Instead, the shell expands y* and places each file that matches the glob as an argument to ls, so you'd really be running

ls y01.sh y02.sh y03.sh y04a.sh y04.sh y.sh ytq

when you typed

ls y*

You could see the same effect using other commands too. echo for example will print each argument it's given, so you can simulate ls y* by doing echo y* (though echo won't show the contents of any directories that start with y)

Eric Renouf
  • 13,950
  • 3
  • 45
  • 67
  • Thank you. I tried using the approach set out by @runlevel0 here https://stackoverflow.com/questions/12711786/bash-convert-command-line-arguments-into-array and realised that the problem was occurring before the function started work on the parameter list. This pointed me to http://www.tldp.org/LDP/abs/html/globbingref.html which expands on your explanation. As is so often the case, the root cause is not where one expects! – user8150417 Jun 12 '17 at 21:21
  • As the problem arises with globbing outside the function, it can't be fixed by anything inside the function. The response by @TaxpayerZombies to this question https://ksearch.wordpress.com/2010/09/23/wildcard-expansion-bash-shell/ pointed in the right direction - setting an alias that briefly disables globbing. `alias y='set -o noglob;yy';yy(){ ~/y.sh “$@”;set +o noglob;}` – user8150417 Jun 13 '17 at 09:25