0

Trying to parse all arguments to one string but my code is only giving me errors that it can't find i:

test: line 3: =: command not found
test: line 7: [i: command not found
test: line 7: [i: command not found
test: line 7: [i: command not found
test: line 7: [i: command not found
test: line 7: [i: command not found

Code bellow

#!/bin/sh

$msg=""

for i in $@
do
if [i -gt 1]; then
    msg="$msg $i"
fi
done

EDIT: thx for all the help, got it to work. My final solution if anyones interested:

#!/bin/sh

args=""
for i in "${@:2}"
do
    args="$args $i"
done
1
  • 2
    The first error (test: line 3: =: command not found) comes from an error in the assignment of msg: replace line 3 with msg="" (no dollar, this is shell, not Perl or PHP). Commented Sep 21, 2015 at 8:49

3 Answers 3

3

Your specific error messages are showing up because:

  • assigning to a variable is not done with the $ character as in $msg="", instead you should be using msg=""; and

  • [ is actually a command, one that should be separated from other words by white space, so that the shell doesn't think you're trying to execute some mythical [i command.

However, you have a couple of other problems. The first is that the value of i needs to be obtained with $i, not just i. Using i on its own will give you an error along the lines of:

-bash: [: i: integer expression expected

because i itself is not a numeric value.

Secondly, neither i nor $i is going to be an index that you can compare with 1, so your $i -gt 1 expression will not work. The word $i will expand to the value of the argument, not its index.


However, if you really want to process all but the first element of your argument list, bash has some very C-like constructs which will make your life a lot easier:

for ((i = 2; i <= $#; i++)) ; do   # From two to argc inclusive.
    echo Processing ${!i}
done

Running that with the arguments hello my name is pax, will result in:

Processing my
Processing name
Processing is
Processing pax

For constructing a string containing those arguments, you could use something like:

msg="$2"                           # Second arg (or blank if none).
for ((i = 3; i <= $#; i++)) ; do   # Append all other args.
    msg="$msg ${!i}"
done

which will give you (for the same arguments as above):

[my name is pax]

Although, in that case, there's an even simpler approach which doesn't involve any (explicit) loops at all:

msg="${@:2}"
Sign up to request clarification or add additional context in comments.

3 Comments

If you are using bash then why are you using eval echo \$$i instead of ${!i}
@999999999999999999999999999999: because, up till now, I've never known of that one, always using eval for indirection. Changed answer to use this "new" method, that should make my code much cleaner going forward as well :-) Cheers.
While we're at it: if you all you want to do is to concatenate all arguments (leaving the first one out), you might as well ditch all this and use this parameter expansion: msg="${@:2}".
2

You don't actually need a loop for your specific output (assuming a single string is actually the correct output):

args="${@:2}"  # Use @ instead of * to avoid IFS-based surprises

However, if you plan on iterating over the arguments later, a flat string is the wrong approach. You should be using an array:

args=( "${@:2}" )

3 Comments

Note that args=${*:2} might be surprising if IFS has been changed… args="${@:2}" (with quotes) should be less surprising.
Good point; this is one case where I don't think there is a difference between quoting $@ and not quoting it as well.
On 4.3.11(1)-release, f() { local IFS=; a=${@:2}; echo "$a"; }; f a b c d yields bcd, whereas f() { local IFS=; a="${@:2}"; echo "$a"; }; f a b c d yields b c d (as expected)…
1

[ is just (more or less) an alias for test, so you should use it like a regular command. What I want to say is, that you need whitespaces before and after [ like this:

if [ $i -gt 1 ]; then

Also you forgot the $ before i in the if clause.

6 Comments

Should really quote variable when using [] or alternatively just use [[]] as it is bash.
It looks like you're trying to use $i as an index into your command arguments. That won't work. $i is the actual argument itself. Use shift to discard the first argument and move all the others one place to the left. Then you can just do `msg="$@"
I think OP also don't know how to assign variable. About $msg="" :)
Nope ive litteraly coded in sh in 5 minutes :) Got it to work now, thx anyway
@Prototype From bash manual page: A variable may be assigned to by a statement of the form: name=[value]. So assign variable should without dollar. ;)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.