Bash: for loop in Makefile: unexpected end of file - bash

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.

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

Related

I Can't Figure Out Why I'm Getting These Errors

Errors:
./themezip: line 8: unexpected EOF while looking for matching `''
./themezip: line 11: syntax error: unexpected end of file
My Code:
cat ~/scripts/script-files/repos.txt | xargs -I % sh -c git clone %' && ls
ls -d ~/themes/* > ~/scripts/script-files/dirs
lines=$(wc --lines ~/scripts/script-files/dirs)
sed s/.$// ~/scripts/script-files/dirs > ~/scripts/script-files/dirs1
paste ~/scripts/script-files/dirs1 ~/scripts/script-files/dirs > ~/scripts/script-files/dirs2
cat ~/scripts/script-files/dirs1 | xargs -I % sh -c 'zip -r -q ~/themes/% ~/themes/%/'
cat ~/scripts/script-files/dirs1 | xargs -I % sh -c 'rm -r ~/themes/%/'
rm ~/scripts/script-files/dirs*
The message should be rather clear: you are missing a '. And at the end of the file, you have not closed the last quotes, so the End Of File is a syntax error.
Finding the place where you missed a quote is sometimes tricky. shellcheck.net can help you find the place where it probably went wrong. Most Linux distributions also have a package shellcheck, which does basically the same.
Shellcheck will give some more hints, like the useless use of cat and the fact that lines is never used.
Personally, I would also put the sed pattern in single quotes, even though shellcheck does not mention it.
And, as #user2182349 stated in the comments, the quote is missing at the first line.

Makefile : Assign $(filter-out $#,$(MAKECMDGOALS)) into custom variable [duplicate]

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.
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

Bash if-condition inside Makefile on macOs BigSur gives syntax error: unexpected end of file [duplicate]

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.
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

How do I read BASH parameters correctly from a file?

I have this configuration file in my CI where I'm specifying a header file and some CMAKE flags on one line.
The configuration file looks like this (filelist):
./settings6.h -DMY_COMPILE_FLAGS="-m32 -fstrict-aliasing"
./settings7.h -DMY_FEATURE_1=ON
./settings8.h -DMY_FLAG=ON -DMY_FEATURE_2=ON -DMY_INCLUDE_DIR=/usr/include/
Now, I'm using a bash script to process this configuration file:
#!/bin/bash
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
while read i; do
HEADERFILE=$(echo $i | cut -d ' ' -f 1)
CMAKEFLAGS=$(echo $i | cut -s -d ' ' -f 2-)
if [[ "$HEADERFILE" == "" ]]; then
continue
fi
CFLAGS="-Werror" cmake "my_build_dir" "$CMAKEFLAGS" -G "Ninja" -DMY_EXTRA_INCLUDE="$SCRIPTDIR/$HEADERFILE" -B"build_env_dir" > /dev/null
ninja -C "build_env_dir"
done <<ENDOFINPUT
$(grep -v '^#' $SCRIPTDIR/filelist)
ENDOFINPUT
When I have the bash script as above, the line with settings6.h gets processed properly, i.e. the MY_COMPILE_FLAGS are set to -m32 -fstrict-aliasing.
However, settings8.h is failing because the value of MY_FLAG is seen by CMAKE as ON -DMY_FEATURE_2=ON -DMY_INCLUDE_DIR=/usr/include/, so MY_FEATURE_2 and MY_INCLUDE_DIR are not processed correctly.
After googling around a bit, I thought, well, surely a quoting issue, probably I have to remove the quotes around $CMAKEFLAGS like this:
CFLAGS="-Werror" cmake "my_build_dir" $CMAKEFLAGS -G "Ninja" -DMY_EXTRA_INCLUDE="$SCRIPTDIR/$HEADERFILE" -B"build_env_dir" > /dev/null
In fact, this lets settings8.h work as expected (all three options are processed), but now, settings6.h is suddenly failing since CMAKE complains:
CMake Error: The source directory "/src/-fstrict-aliasing"" does not exist
Can someone guide me please how I read the settings correctly from my filelist so that settings6.h and settings8.h both succeed?
Here's a Makefile which refactors this into a sequence of recipes.
Cases := $(patsubst %.h,%,$(wildcard ./settings*.h))
all_done := $(patsubst %,.%.done,$(Cases))
.PHONY: all
all: $(all_done)
cases.mk: filelist.txt
sed 's%^\./%case_%;s% % := %' $< >$#
include cases.mk
.%_done: ./%.h
CFLAGS="-Werror" cmake "my_build_dir" $(case_$*) -G "Ninja" \
-DMY_EXTRA_INCLUDE="$<" -B"build_env_dir" > /dev/null
ninja -C "build_env_dir"

Bash - bad substitution

I have a short bash script to get source code's dependency files.
#!/bin/sh
rule=$(cpp -P -w -undef -nostdinc -C -M file.cc)
rule=${rule##*:}
#echo $rule
echo ${rule//\\}
Unfortunately, it outputs ./findDep.sh: 5: ./findDep.sh: Bad substitution.
But if I uncomment echo $rule, the script will execute without any problem:
lib.h macro.inc fundamental.h lib/fs.h lib/net.h \ lib/net/fetch.h
lib.h macro.inc fundamental.h lib/fs.h lib/net.h lib/net/fetch.h
Any one know why?
Thanks in advance.
You should change #!/bin/sh to #!/bin/bash or #!/usr/bin/env bash.
I can't reproduce your problem here with Bash 4.2.29.
However, did you know that read will join lines with \ newline continuations by default?
read rule < <(cpp -P -w -undef -nostdinc -C -M file.cc)
echo "${rule##*:}"
Or, in a more sh-compatible way (I think),
cpp -P -w -undef -nostdinc -C -M file.cc | {
read rule
echo "${rule##*:}"
}

Resources