0

I want to create a for loop that runs from 1 to a number stored in a variable. But it produces this error:

Syntax error: Bad for loop variable

This is my script:

#!/bin/bash

count_lines () 
{
  local f=$1  
  l=`wc -l $f | sed 's/^\([0-9]*\).*$/\1/'`
}
echo "$0 counts the lines of code" 
l=0
while [ "$*" != ""  ]
do
        count_lines $1
        echo "$1: $l"
        shift
done
for(( i= 0 ; i <= ${l} ; i++))
do
   title=$(grep -oPm1 "(?<=<title>)[^<]+" <<< "$0")
   echo "$title"
done
Yuces
  • 1
  • Small trick: wc -l <filename (note the left-angle) outputs just the count and you don't need to fiddle with sed or even something cheaper like ${var% *}. That said, if you really want to look for XML construct(s?) in the file(s?) they are unlikely to be related to the number of lines; one of the main features of XML is that it is stream-oriented, not line-oriented. – dave_thompson_085 Dec 06 '15 at 02:20
  • for (( i= 0 ; i <= ${l} ; i++)) space missing here. And in (( )) use i <= l -- ${} is unnecessary and a missing l actually messes up with the syntax. – Mingye Wang Dec 09 '15 at 03:18

2 Answers2

1

Make sure that the script is executable, and run the script by just typing the command, including its path. For example, if the script is called foo and is in the current directory, run

./foo

Given the error message, you are doing something like sh foo. This runs the script under sh, not bash. sh on your machine is a different shell, probably dash, which doesn't support the for loop syntax you used. By running ./foo, your script will be executed by the shell mentioned in the first line, which is bash.

Your script is weird in several places:

  • Always put double quotes around variable substitutions: "$1", "$f", etc.
  • That while [ "$*" != "" ] … loop is a very roundabout way of iterating over the arguments of the script. The simple, idiomatic way is

    for x; do
      count_lines "$x"
    done
    

    or

    for x in "$@"; do
      count_lines "$x"
    done
    
  • I'm not sure what you're trying to do with title=$(grep -oPm1 "(?<=<title>)[^<]+" <<< "$0"); "$0" is the path to the script, so you're searching the regexp (?<=<title>)[^<]+ in the path to the script, which doesn't make much sense.
  • I'm trying to extract a value from an xml document that has been read into my script as a variable with title=$(grep -oPm1 "(?<=)[^<]+" <<< "$0") – Yuces Dec 05 '15 at 23:21
  • and I wish to extract the all values between titles with a loop – Yuces Dec 05 '15 at 23:22
  • @engineer Fix the parts you understand, then post a new question with your updated script, some sample input, and the desired output. – Gilles 'SO- stop being evil' Dec 05 '15 at 23:30
  • I test my machine's shell with ps -p $$ and it is bash @Gilles – Yuces Dec 05 '15 at 23:30
  • @engineer That shows you which shell you're running interactively. But given the error message you got, you are not running the script with bash. Once again, run /path/to/script instead of sh /path/to/script or whatever it is you're doing. – Gilles 'SO- stop being evil' Dec 05 '15 at 23:33
  • @ Gilles runing with /path/to/script didn't show anything no strings,no error...etc – Yuces Dec 05 '15 at 23:40
  • @engineer Having no error is progress. Now you need to fix your script to do what you actually want. Your grep command isn't searching in the input files, so it's not surprising that you aren't finding anything. Once again, please stop commenting here and ask a new question with your updated script, some sample input, and the desired output. – Gilles 'SO- stop being evil' Dec 05 '15 at 23:43
0

The main problem I believe is with not testing if the file actually exists and getting a count l that is invalid for the for loop.

Take a look at this (very modified) similar script to give you some ideas:

#!/bin/bash

count_lines() {
if [[ -r $1 ]]; then     # if the file exist.
  l="$(wc -l "$1")"      # count the number of lines.
  l="${l%%[^0-9]*}"      # remove anything that is not a digit from the end.
else
  l=0
fi
}
echo "$0 counts the lines of code"

for file; do               # while there is an argument.
  count_lines "$file"    # execute the function above
  echo "$file: $l"       # print the number of lines.
done

echo "$(grep -oPm1 "(?<=<title>)[^<]+" "$0")"

I can not understand why you try to run l times a command (grep) to find title inside a file. One time is enough.

Also, the grep command is reading the script (not an external file).

As Gilles said: heavily correct your code, post a new question.