1

I am trying to iterate through an array created after some command execution. The code used is:

#!/bin/bash
mailx -H|grep '^ [UN]'>ListOfMessages.txt
msgNumbers=`cut -c 4-5 ListOfMessages.txt`
echo $msgNumbers
for msg in "${msgNumbers[@]}";
do
echo $msg;
echo $msg|mailx;
done

The ListOfMessages.txt look like:

 U  5 Sender1    Thu Aug 23 14:28  179/10454 Incident
 U  7 Sender2    Thu Aug 23 15:20  179/10456 Incident
 U  8 Sender3    Thu Aug 23 15:41  192/10801 Incident
 N  9 Sender4    Thu Aug 23 15:45  197/11011 Incident

The array is getting updated with the numbers 5 7 8 9 as required. I keep getting "Bad Substitution" error(at the line where for loop starts).

Please advise me on the she-bang to be used.

1

4 Answers 4

2

As far as I can see, you have no array in your code. The variable msgNumbers is a string that holds the output of your cut command.

To iterate over the output of cut, use

#!/bin/bash

mailx -H | grep '^ [UN]' | cut -c 4-5 |
while read msg; do
    print 'msg = %s\s' "$msg"
done

This sends the output of cut into the while loop immediately following it, through the pipe (|). The while loop will iterate with msg set to each individual line of output from cut.

The cut gets its data directly from the grep command, which removes the need for storing the data in an intermediate file or variable.

I removed the echo $msg|mailx; command because it did not make much sense to me (the mailx utility needs an address to send the data to).

The grep+cut could also be replaced by a single call to awk where we let awk do the work of both tools and output the second whitespace-delimited column when the regular expression matches:

#!/bin/bash

mailx -H | awk '/^ [UN]/ { print $2 }' |
while read msg; do
    print 'msg = %s\s' "$msg"
done

I'm not commenting further on the use of mailx as it is a non-standard utility which is implemented slightly differently across Unix systems (my version does not have a -H option, for example).


The #!-line looks ok to me, if you want the script to be executed by bash and if the bash executable is located at that path (which it commonly is on Linux systems, for example, but check with command -v bash on your system to be sure). The code I have posted above is compatible with /bin/sh, so bash isn't really needed to run it (it would run in any sh-like shell).

Just make sure that the script is executable and that you run it without specifying an explicit interpreter.

1
  • The OP's probably on Solaris (10 or older) as they get Bourne shell error messages. Aug 23, 2018 at 9:02
0

Don't double quote the msgNumbers reference, and, msgNumbers is not an array, so the indexing is pointless.

2
  • okay...then can you advise me how to store the result of command: cut -c 4-5 ListOfMessages.txt so that I can use the values one by one in a loop?
    – Devjith
    Aug 23, 2018 at 7:19
  • The first half tells how to make the for loop work, and the second half hints on improvement. Had the requestor given the input sample from the beginning, a more detailed answer (or even full blown solution) could have benn provided.
    – RudiC
    Aug 23, 2018 at 9:54
0

Use () to store the value as an array.

msgNumbers=(`cut -c 4-5 ListOfMessages.txt`)
echo "${msgNumbers[@]}"
for msg in "${msgNumbers[@]}";
do
echo $msg;
done
2
  • Tried with your answer....But getting an error: Shell_script.sh: syntax error at line 4: `msgNumbers=' unexpected
    – Devjith
    Aug 23, 2018 at 7:41
  • @Devjith, again, you've tried to interpret the script with sh, not bash. Don't run the script as sh the-script. Do a chmod a+x the-script and then ./the-script Aug 23, 2018 at 9:00
0

The issue is solved. The problem was that msgNumbers was not an indexed array. So I changed the for msg in "${msgNumbers[@]}";to for msg in ${msgNumbers};.Now its working. The rest of the code is same as in my question.

1
  • It's still not an array, and now you rely on the shell doing word splitting of the string in your variable, and filename generation ("globbing") on the words generated by the word splitting. Your code would now break if the IFS variable is set to one or several digits.
    – Kusalananda
    Aug 23, 2018 at 9:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .