0

I have the following code that checks whether either of two input args are supplied, and depending on their existance runs a certain piece of code. I'm running into syntax errors in my if statements however, because I'm getting an unexpected token `else' error

if [ -z "${4}" ] || [ -z "${5}" ]
then
    echo "Missing index argument(s). Defaulting to entire file."
    cat ${devicesFile} | cut -d "," -f 4 | tr [:upper:] [:lower:] | awk '{print substr($1,1,8)"-"substr($1,9,4)"-"substr($1,13,4)"-"substr($1,17,4)"-"substr($1,21,12)}' | while read deviceGuid
else
    i1=${4}
    i2=${5}
    head -n ${i1} ${devicesFile} | tail -n ${i2} | cut -d "," -f 4 | tr [:upper:] [:lower:] | awk '{print substr($1,1,8)"-"substr($1,9,4)"-"substr($1,13,4)"-"substr($1,17,4)"-"substr($1,21,12)}' | while read deviceGuid
fi

Is it an issue with my or condition.? That's the only thing I can really think of. Any help would be greatly appreciated.

//Here's what I had before I tried to add the index parameters, so what HVD said about the broken while makes sense..

cat ${devicesFile}  | cut -d "," -f 4 | tr [:upper:] [:lower:] | awk '{print substr($1,1,8)"-"substr($1,9,4)"-"substr($1,13,4)"-"substr($1,17,4)"-"substr($1,21,12)}' | while read deviceGuid
do
    # now=`date +"%Y%m%d %H%M%S"`
    currentTime=`date +"%H%M%S"`
    currentHour=`date +"%H"`
    currentDate=`date +"%Y%m%d"`
    # create parent directory
    mkdir -p ${crashlogFolder}/${currentDate}/${currentHour}/${crashCode}/
    # create crash log for device
    touch ${crashlogFolder}/${currentDate}/${currentHour}/${crashCode}/${currentTime}_${deviceGuid}.log
done
3
  • 2
    it's an issue with the broken while at the end of that pipeline on the fourth line. Commented Aug 21, 2014 at 14:06
  • Always use double quotes around your variable interpolations unless you specifically require the shell to perform token splitting and wildcard expansion on the values. Commented Aug 21, 2014 at 14:17
  • if $devicesFile is a file on your system, you can replace cat ${devicesFile} | cut -d "," -f 4 by cut -d "," -f 4 ${devicesFile} as cut can read from file: manpages.ubuntu.com/manpages/precise/en/man1/cut.1.html Commented Aug 21, 2014 at 14:25

3 Answers 3

5

You cannot mix control structures like that. If you originally had

a | while b
do
  c
done

and now you want a to be customisable, you cannot do

if d
then
  e | while b
else
  f | while b
fi
do
  c
done

Shells just don't work like that. (Nor do most other languages.) while b; do c; done was a single statement, and cannot be broken up like that.

Instead, you should change it to

if d
then
  e
else
  f
fi | while b
do
  c
done

The whole if d; then e; else f; fi is a single statement, and its output, regardless of which of the commands it comes from, will be piped to the while statement.

Sign up to request clarification or add additional context in comments.

3 Comments

In addition, you would probably want to refactor the tr | awk to outside the fi so that you can avoid code repetition.
I've edited my question to provide a bit more info, I see the issue with the while statement though. Would just simply putting a do block in the then and else statements work.?
@MrTunaDeluxe Yes, it's possible to copy the do...done into both branches of the if statement, but that would cause even more code duplication, so I wouldn't recommend it.
4

You're lacking a body to your while block, it should have the form while <condition>; do <actions>; done

if [[ -z "${4}" || -z "${5}" ]]; then
    # …
    cat ${devicesFile} \
    | … \
    | while read deviceGuid; do echo $deviceGuid; done
else
    # …
    head -n ${i1} ${devicesFile} \
    | … \
    | while read deviceGuid; do echo $deviceGuid; done
fi

Explaination

  1. used bash test [[ … ]] so you can use the boolean OR inside as [[ … || … ]], discard if you need portability;
  2. replaced some of your command by just for clarity
  3. escaped newline, \ at the end of line (no spaces must follow), to get a clearer script
  4. added missing block with dummy echo $deviceGuid command.

2 Comments

Since | is not a command terminator, you can end a line with | instead of using an explicit line continuation character and starting the next line with |.
@chepner nice, I will try that when using bash in makefile. However I like the way the pipe at the beginning make it look like a thread and a logical continuum.
3

This is really a comment on Édouard Lopez's answer: DRY -- pull out all the common code:

if [[ -z "${4}" || -z "${5}" ]]; then
    cat ${devicesFile} 
else
    head -n ${i1} ${devicesFile} | tail -n ${i2}
fi |
  cut -d "," -f 4 | 
  tr [:upper:] [:lower:] | 
  awk -F, '{print substr($1,1,8)"-"substr($1,9,4)"-"substr($1,13,4)"-"substr($1,17,4)"-"substr($1,21,12)}' |
  while read deviceGuid; do 
    : 
  done

Note to MrTunaDeluxe: ${var} is different from "$var" -- you should prefer the latter. The first form is required for array element expansion, the various parameter substitutions, and also to disambiguate the variable from surrounding text (e.g. echo "${var}text"), but just using braces will not prevent word splitting or filename expansions.

Comments

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.