Makefile executes $(shell command) unordered [duplicate] - shell

This question already has answers here:
How to run sub Shell script in Makefile?
(2 answers)
Closed 2 years ago.
I am having an issue with my Makefile:
At the begining of the Makefile, a file is created.
I wanna retrieve the content of that created file by using the "cat command".
I need to use the $(shell cat) execution because I have to retrive it inside another command.
It's like if the sub-shell does not reallize of the creation of that file and does not find it.
If you take a look into the output message order... its like first of all, it is executing the $(shell cat) command, because the first line is saying: "cat: test.txt: The file or directory does not exist".
Why it seems to be executing the commands unordered... executing first the $(shell cat)...
It could be shown in the following silly example:
Take a look into the following Makefile with a test routine:
test:
rm -rf test.txt
echo "Hello World" > test.txt
echo "$(shell cat test.txt)"
Executing make test the Output is as follows:
cat: test.txt: The file or directory does not exist.
rm -rf test.txt
echo "Hello World" > test.txt
echo ""
If you execute "make test" twice, you can realize that the second execution of the Makefile is echoing the text "Hello World"... because it is executing $(shell cat test.txt) at the begining and the file exists from the frist "make test" execution...
Any suggestion about what is happening and how I have to proceed to accomplish my goal?
Many thanks in advance!

Double up your $s to escape them, so they're still seen by the shell in literal form (and thus executed by the shell, not by make prior to the shell's invocation):
test:
rm -rf test.txt
echo "Hello World" > test.txt
echo "$$(cat test.txt)"

Related

How to execute a test as part of bash string as executable command?

If I have a "file" that includes...
rm -rf /etc/motd
if [ -f /etc/motd]; then rm -rf /etc/motd; fi
And I try to do...
while read -r line
do
command ${line}
#$(${line})
#eval ${line}
done< "file"
The 1st line runs of course. But the 2nd command fails with if : command not found. Which I understand the error because not an explicit command. So the question is how to execute a test as part of a string as bash script logic? I tried eval, and $(), i.e. subshells, but still errors out? Tripping over the 'if' test. I need a conditional test before the command/script code is executed in a one-liner. There has to be a way to do this, right?
If your intention is to load and execute "file" from another script just do
source "file"
no need to loop over the lines.

Rules of executing shell command in Makefile

When I executed command make, I got an error message
Makefile:4: *** missing separator. Stop.
The command in Makefile is:
$(shell ./makejce common/jce jce)
What's wrong with it?
-------makejce---------
#!/bin/bash
FLAGS=""
local_protoc=""
dir0=`pwd`
dir=`pwd`
......
if [ $# -gt 1 ]
then
mkdir -p $2
cd $2
dir=`pwd`
cd $dir0
fi
cd $1
jce_dir=`pwd`
#sub dir
for d in `ls -d */`
do
if [ -d $d ]
then
cd $d
for f in `find . -name '*.jce'`
do
${local_protoc} ${FLAGS} --dir=${dir} $f
done
cd $jce_dir
fi
done
#current dir
for f in `ls *.jce`
do
${local_protoc} ${FLAGS} --dir=${dir} $f
done
cd $dir0
-----makefile------
......
$(shell ./makejce common/jce jce)
......
With so little info it looks extremely bizarre (why are you running all the build steps in a shell script then invoking that script with a shell makefile function? The entire point of a makefile is to manage the build steps...) but without more information I'll just answer your specific question:
The make shell function works like backticks or $(...) in shell scripts: that is it runs the command in a shell and expands to the stdout of the command.
In your makefile if you have:
$(shell echo hi)
then it runs the shell command echo hi and expands to the stdout (i.e., hi). Then make will attempt to interpret that as some makefile text, because that's where you have put the function invocation (on a line all by itself). That's a syntax error because make doesn't know what to do with the string hi.
If you want to run a shell function then either (a) redirect its output so it doesn't output anything:
$(shell ...command... >/dev/null 2>&1)
or (b) capture the output somewhere that it won't bother make, such as in a variable like this:
_dummy := $(shell ...command...)
(by using := here we ensure the shell function is evaluated when the makefile is parsed).

Bash: passing a variable to mv command option

--Bash 4.1.17 (running with Cygwin)
Hello, I am trying to pass the date into the --suffix option on the move (mv) command. I am able to pass in a simple string (like my name) but unable to pass in the date. If you run the script below you will see that the mv command with the suffix="$var" works but suffix="$now" does not.
#!/bin/bash
dir="your directory goes here"
now="$(date "+%m/%d/%y")"
var="_CARL!!!"
echo "$now"
echo "$var"
cd "$dir"
touch test.txt
# error if already exists
mkdir ./stack_question
touch ./stack_question/test.txt
mv -b --suffix="$var" test.txt ./stack_question/
The idea is that if test.txt already exists when trying to move the file, the file will have a suffix appended to it. So if you run this script with:
--suffix="$var"
you will see that the stack_question directory contains two files:
test.txt & test.txt_CARL!!!
But, if you run this script with:
--suffix="$now"
you will see that in the stack_question directory only contains:
test.txt
Any help on this would be greatly appreciated!
It is because you have embedded / in your date format try
now="$(date +%m_%d_%y)"

ksh: How to pass arguments containing white space between scripts?

I have two scripts (one ksh and other Perl) and one calls the other. I have to handle a scenario when someone accidentally enters a white space in file name and report it as an error (only when the file does not exist). It looks like p.sh which uses $* to pass/forward all arguments to p.pl doesn't handle quoted arguments the way they should be? Any ideas how to fix this? Let's just say one could enter multiple spaces in the filename too.
p.sh:
#!/usr/bin/env ksh
/tmp/p.pl $* 1>/tmp/chk.out 2>&1
print "Script exited with value $?"
print "P.PL OUTPUT:"
cat /tmp/chk.out
exit 0
p.pl:
#!/usr/bin/perl -w
use Getopt::Std;
getopts ("i:", \ %options);
if ($options{i} && -e $options{i}) {
print "File $options{i} Exists!\n";
}
else {
print "File $options{i} DOES NOT exist!\n";
}
Test cases (when there is an actual file '/tmp/a b.txt' (with a space in it) on the system):
[test] /tmp $ p.pl -i /tmp/a b.txt
File /tmp/a DOES NOT exist!
[test] /tmp $ p.pl -i "/tmp/a b.txt"
File /tmp/a b.txt Exists!
[test] /tmp $ ./p.sh -i "/tmp/a b.txt"
Script exited with value 0
P.PL Check OUTPUT:
File /tmp/a DOES NOT exist!
[test] /tmp $ ./p.sh -i "/tmp/ a b.txt"
Script exited with value 0
P.PL Check OUTPUT:
File /tmp/ Exists!
It's the last two scenarios I'm trying to fix. Thank you.
To preserve whitespace that was passed into the script, use the $# parameter:
/tmp/p.pl "$#" 1>/tmp/chk.out 2>&1
The quotation marks are necessary to make sure that quoted whitespace is seen by p.pl.

Makefile as an executable script with shebang?

Is it possible to create an executable script that would be interpreted by make?
I tried this:
#!/usr/bin/env make --makefile=/dev/stdin
main:
#echo Hello!
but it does not work - hangs until press Ctrl-c.
#!/usr/bin/make -f
main:
#echo Hello World!
Is normally all you need in a standard make file. The filename is implicitly passed as the last argument. /dev/stdin here is (usually) the tty. You can do the whole env thing if there's a reason to, but often there's no need.
ajw#rapunzel:~/code/videocc/tools > vi Makefile
ajw#rapunzel:~/code/videocc/tools > chmod a+x Makefile
ajw#rapunzel:~/code/videocc/tools > ./Makefile
Hello World!
The following adds a level of indirection but it's the best solution I've come up with for self-executing makefiles not called "makefile":
#!/bin/sh
exec make -f- "$#" << 'eof'
.PHONY: all
all:
#echo 'hello world!'
I'm trying to collect #! env hacks for each language / program here.

Resources