Search code examples
shellposixcommand-line-argumentsdash-shell

Why does "echo" ignore its first argument sometimes?


The output of this code seems to depend on the option I give (-n or -a) but I simply don't understand the reason. Here's the portion of the code that doesn't work (just the code itself + outputs):

#!/bin/sh

FILE="/path/to/some/textfile"

[ $# -eq 0 ] && echo "No arguments. Exiting.." && exit 1
[ $1 != "-n" ] && [ $1 != "-a" ] && echo "No new default usernames. Exiting" && exit 1
echo $@
echo
newusernames=`echo "$@"|cut -d' ' -f2-`
printf "'$newusernames' $mode as default usernames in $FILE\n"

Running it and giving some arguments in both ways:

scriptname -a word1 word2 word3

Gives:

-a word1 word2 word3

'word1 word2 word3'  as default usernames in path/to/textfile

While..:

scriptname -n word1 word2 word3

Gives:

word1 word2 word3
'word2 word3'  as default usernames in path/to/textfile

$mode is just a var that should be set in either two cases. As shown the output is really different while this shouldn't happen.

Please note that I'm aware that this is not the most correct way to pass shell arguments in a script. I'm just trying to understand the reason for this behaviour.


Solution

  • Your second case expands to this:

    echo -n word1 word2 word3
    

    and echo -n can be special (and seems to be, in this case): it's interpreted as an option to echo to not print a trailing newline character.

    One solution could be to use

    shift
    newusernames=$(echo "$*")
    

    to remove the parameter first, or even more robust:

    shift
    newusernames=$(printf '%s' "$*")
    

    In Bash, you'd have fancier options such as

    printf -v newusernames '%s' "${*:2}"
    

    to do everything in one step.