0

I am relatively new to shell, and I am getting a syntax error where I am still confused.

#!/bin/dash

ls="ls -l test"
small=0
medium=0
large=0

for i in $(seq 11 9 56)
do
    filename=$(echo $($ls) | cut -d ' ' -f $i)
    count=$(wc -w test/$filename | cut -d ' ' -f 1)
    if [ "$count" -lt 10 ]; then
        small=(( $small+1 ))
    elif [ "$count" -gt 100 ]; then
        large=(( $large+1 ))
    else
        medium=(( $medium+1 ))
    fi
done
echo $small
echo $medium
echo $large

In this code, I am trying to get a list of files, retrieve how many words a file has, and sort them into small/medium/large size files. I am pretty sure I haven't made any syntax errors for incrementing the variables using test, but they don't seem to work within an if statement. Can anyone help me out with this? There is a syntax error when using multiple brackets within an if statement, but I have no idea what it is.

4
  • 1
    I don't know dash very well, but small=(( $small+1 )) should probably be small=$(( $small+1 )). I.e., you want the variable small to be assigned the value that comes from the arithmetic operation $small + 1. The lines with assignments to medium and large would benefit from the same syntax change. Commented Jun 17, 2023 at 17:26
  • 1
    The shell tells you on which line the error occurs. Did you think it was a good idea not to tell us? Commented Jun 17, 2023 at 18:29
  • 2
    Always paste your script into https://shellcheck.net, a syntax checker, or install shellcheck locally. Make using shellcheck part of your development process. Commented Jun 17, 2023 at 18:31
  • 2
    If you redirect the file like wc -w < test/$filename, it will not print the filename, so you won't need to cut it off. Also, inside $(( ... )) words are assumed to be variables: small=$(( small + 1 )) is enough. Commented Jun 17, 2023 at 22:45

2 Answers 2

0

The syntax is:

large=$(( $large + 1 ))

Or even better:

large=$(( large + 1 ))

Not large=(( $large+1 )).

Korn-like shells also have (( large = large + 1 )) or (( large += 1 )) or (( large++ )) but even though POSIX specified ksh's the $((...)) arithmetic expansion operator for sh, they left out the ((...)) arithmetic expression operator, so dash didn't bother implement it.

In any case, the rest of your script doesn't make much sense either. You probably meant something like:

#! /bin/sh -

small=0 medium=0 large=0
for file in test/*; do
  words=$(wc -w < "$file") || continue
  if [ "$words" -lt 10 ]; then    # 0 to 9
    small=$(( small + 1 ))
  elif [ "$words" -gt 100 ]; then # 101 and above
    large=$(( large + 1 ))
  else                            # 10 to 100
    medium=$(( medium + 1))
  fi
done

printf '%s\n' "$small" "$medium" "$large"

You could also do something like:

...
  if [ "$words" -lt 10 ]; then    # 0 to 9
    kind=small
  elif [ "$words" -gt 100 ]; then # 101 and above
    kind=large
  else                            # 10 to 100
    kind=medium
  fi
  : "$(( $kind += 1 ))"
...

Where the arithmetic expansion has the side effect of incrementing the value of the variable whose name is stored in $kind, and we discard the result of that expansion by passing it to the : null-command, so in effect it's similar to the ksh-style (( $kind += 1 )).

0

You need var=$(( expr )) instead of var=(( expr ))

( is a control operator for dash i.e. it separates words. So var=(... cannot make sense because it becomes var= (...

(( is known to (e.g.) bash but not to dash so it's not surprising that this does not work.

It does not work in bash either as bash allows variable assignments in simple commands only but in front of a compound command (like (( ))).

You must log in to answer this question.