Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: for loop in Makefile: unexpected end of file

Tags:

bash

makefile

I am writing a Makefile, which will list all headers included by a.cpp, b.cpp and c.h files. However, I got the error of unexpected EOF. Similar questions are always caused by the line terminator, like they used CRLF instead of LF for an EOL. However, my Text editor was set to using LF and I recheck this by delete all EOL and re-added. Unfortunately, the error still remains. Here are the codes:

#!/bin/bash

list-header:
    for file in a.cpp b.cpp b.h
    do
        echo "$file includes headers: "
        grep -E '^#include' $file | cut -f2
    done

I got this error message:

for file in "Bigram.cpp client.cpp Bigram.h"
/bin/sh: -c: line 1: syntax error: unexpected end of file"

Thanks in advance for any help.

like image 269
Baozi CAI Avatar asked May 23 '15 12:05

Baozi CAI


People also ask

What is Unexpected end of file in Bash?

An Unexpected end of file error in a Bash script usually occurs when you there is a mismatched structure somewhere in the script. If you forget to close your quotes, or you forget to terminate an if statement, while loop, etc, then you will run into the error when you try to execute your Bash script.

How do you run a loop in a shell script?

1) Syntax:Syntax of for loop using in and list of values is shown below. This for loop contains a number of variables in the list and will execute for each item in the list. For example, if there are 10 variables in the list, then loop will execute ten times and value will be stored in varname.

What is set in Bash?

The set command in Bash allows you to control the behavior of your scripts by managing specific flags and properties. These safeguards guarantee that your scripts are on the right track and that Bash's odd behavior does not cause problems.


1 Answers

First note you have to escape $ that you want the shell to see, otherwise make will expand them before calling the shell. However, your main problem is that every logical line in a make recipe is a separate shell command. So, this rule:

list-header:
        for file in a.cpp b.cpp b.h
        do
            echo "$file includes headers: "
            grep -E '^#include' $file | cut -f2
        done

will cause make to invoke the shell commands:

/bin/sh -c 'for file in a.cpp b.cpp b.h'
/bin/sh -c 'do'
/bin/sh -c 'echo "ile includes headers: "'
/bin/sh -c 'grep -E '^#include' ile | cut -f2'
/bin/sh -c 'done'

You need to use backslashes to "continue" a logical line across newlines if you want them all sent to the same shell, and you have to add semicolons to make that work since the newlines no longer serve as command delimiters:

list-header:
        for file in a.cpp b.cpp b.h; \
        do \
            echo "$$file includes headers: "; \
            grep -E '^#include' $$file | cut -f2; \
        done
like image 91
MadScientist Avatar answered Sep 20 '22 11:09

MadScientist