The command with double quotes in the shell cannot be executed - shell

When I execute the following script, it will report an error, but if I manually execute the command of the echo, I will not report an error, they are clearly the same!
I tried to execute this script in Linux, Windows, they all report the same error. Although there is no command MinGW Makefiles on Linux, it will appreciate that even if there is, it will be reported. Because the error prompt is Could not create named generator "MinGW instead of Could not create named generator "MinGW Makefiles"
How can I fix this problem?
#!/bin/bash
compiler_options=(' -G "MinGW Makefiles"')
echo "cmake -S . -B build ${compiler_options}"
cmake -S . -B build ${compiler_options}
# run command
bash test.sh
# errorinfo
CMake Error: Could not create named generator "MinGW

The point of using an array is to avoid cramming all the arguments into a single whitespace-delimited string.
#!/bin/bash
compiler_options=(-G "MinGW Makefiles")
echo "cmake -S . -B build ${compiler_options[*]}"
cmake -S . -B build "${compiler_options[#]}"

Related

Running command with make gives different result from running it directly in shell

I have a Makefile that looks like this:
build-docker:
DOCKER_BUILDKIT=1 docker build --ssh default=~/.ssh/id_rsa -t my-app .
If I run make build-docker I get the following error:
$ make build-docker
DOCKER_BUILDKIT=1 docker build --ssh default=~/.ssh/id_rsa -t my-app .
could not parse ssh: [default=~/.ssh/id_rsa]: stat ~/.ssh/id_rsa: no such file or directory
make: *** [Makefile:12: build-docker] Error 1
However, if I run the command directly in the shell it runs just fine:
$ DOCKER_BUILDKIT=1 docker build --ssh default=~/.ssh/id_rsa -t my-app .
[+] Building 65.5s (20/20) FINISHED
Why is this and how do I solve it?
You are running the same command, but in different shells. Your interactive shell is probably bash. But the shell make uses is /bin/sh which is a POSIX standard shell (often).
The special handling of ~ in an argument is a shell feature: it's not embedded in programs like docker or ssh. And, it's not defined in POSIX; it's an additional feature that some shells, like bash.
On my system:
bash$ echo foo=~
foo=/home/me
bash$ /bin/sh
$ echo foo=~
foo=~
To be portable you should use the full pathname or $HOME instead (remember that in a make recipe you have to double the $ to escape it from make: $$HOME).

Shell Commands Using ( on Makefile

I'm preparing some latex files and decided to make some makefile to help me to compile and clean de latex files. So I created the following makefile
aula=listaProb
all: compile clean
compile:
pdflatex $(aula).tex
clean:
rm -rf !(makefile|$(aula).tex|$(aula).pdf) -v
But when I execute "make" I get the following mistake
rm -rf !(makefile|listaProb.tex|listaProb.pdf) -v
/bin/sh: 1: Syntax error: "(" unexpected
makefile:8: recipe for target 'clean' failed
make: *** [clean] Error 2
But the command
rm -rf !(makefile|listaProb.tex|listaProb.pdf) -v
works fine on the terminal.
What is wrong? I can't find any mistake :/..
Ps. I use this way to remove the files because I want to delete all but the specified files. It needs the command
shopt -s extglob
before use it. If anyone knows how to do it without use extglob, it would be nice.
Thanks
The problem is recipe commands are passed to /bin/sh which cannot process that syntax. You can change your Makefile to say:
clean:
bash -O extglob -c "rm -rf !(makefile|$(aula).tex|$(aula).pdf) -v"
To force this command to be run in bash with extglob on.
Or define SHELL variable for your make e.g. by running:
make SHELL="/bin/bash -O extglob" clean
Or adding:
SHELL := /bin/bash -O extglob
To your make file. The former option only affects shell invocation of that one command, the latter will apply to all your recipes (commands).

Check format for Continous integration

I am trying to write a Makefile command that will output an error if the Go code is not correctly formatted. This is for a CI step. I am struggling with how to get it working in the make file. This solution works on the bash command line:
! gofmt -l . 2>&1 | read
But copying this into the Makefile:
ci-format:
#echo "$(OK_COLOR)==> Checking formatting$(NO_COLOR)"
#go fmt ./...
#! gofmt -l . 2>&1 | read
I get the following error:
/bin/sh: 1: read: arg count
These days, I use golangci-lint, which includes gofmt checking as an option.
But if for some reason you want to do this yourself, the command I previously used for precisely that purpose is:
diff -u <(echo -n) <(gofmt -d ./)
See, for example, the .travis.yml files on one of my projects.

Chisel installation error

While following the tutorial on the Chisel official website for installation, I came to the point where I should test if the installation was done correctly. Doing so yields this error:
set -e -o pipefail; "sbt" -Dsbt.log.noformat=true -DchiselVersion="2.+" "run Parity --genHarness --compile --test --backend c --vcd --targetDir /home/me/chisel-tutorial/generated/examples " | tee /home/me/chisel-tutorial/generated/examples/Parity.out
/bin/bash: sbt: command not found
make: *** [/home/me/chisel-tutorial/generated/examples/Parity.out] Error 127
There is another question regarding the same problem here, where the suggestion to add SHELL=/bin/bash to the Makefile is made. That did not work for me. Another suggestion is to remove set -e -o pipefail: this suggestion actually works but is it OK to remove that option? what does it do?
Edit_1:
I have installed sbt and added its path to the PATH variable.
$ which sbt
/usr/bin/sbt
But still I am getting this error when running make Parity.out
set -e -o pipefail; "sbt" -Dsbt.log.noformat=true -DchiselVersion="2.+" "run Parity --genHarness --compile --test --backend c --vcd --targetDir /home/me/chisel-tutorial/generated/examples " | tee /home/me/chisel-tutorial/generated/examples/Parity.out
/bin/sh: 1: set: Illegal option -o pipefail
make: *** [/home/me/chisel-tutorial/generated/examples/Parity.out] Error 2
If I edit this part of the file suffix.mk:
$(objdir)/%.dot: %.scala
set -e -o pipefail; "$(SBT)" $(SBT_FLAGS) "run $(notdir $(basename $<)) --backend dot --targetDir $(objdir) $(CHISEL_FLAGS)"
$(objdir)/%.out: %.scala
set -e -o pipefail; "$(SBT)" $(SBT_FLAGS) "run $(notdir $(basename $<)) --genHarness --compile --test --backend c --vcd --targetDir $(objdir) $(CHISEL_FLAGS)" | tee $#
By deleting the -o option in the set -e -o pipefail it works, I get the PASSED and [success] message after running $ make Parity.out. So what is going on?
Edit_2:
It is working fine now after I added the SHELL=/bin/bash to the Makefile, so it was first a problem of not having sbt as Nathaniel pointed out then editing the Makefile to include SHELL=/bin/bash.
set -e -o pipefail is a way of making sure that the execution of the bash script both works as expected and that if there is a failure, it halts immediately (rather than at some later stage). Removing it might work - but if there is a failure it might get swallowed and hide the fact it's broken.
But I think your problem lies here, making the other question a bit of a red herring:
/bin/bash: sbt: command not found
Do you have sbt installed on your system? Run which sbt as the user that executes the script. For instance, on my system:
$ which sbt
/opt/local/bin/sbt
If you don't have it on your system, nothing will be returned by running which.
The script clearly needs access to sbt and is failing when it doesn't find it. If you do have it on your system, then there is a mismatch between the user running the script and access to that file. You'll need to post more information about how you're executing the script: in that case it is likely you'll have to update your PATH variables to be able to find the sbt executable.
Given that, after fixing this, you still have a problem, you have to ensure that you're running in bash, and not another terminal type. The reason for this is that bash supports set -o pipefail but a lot of other terminals don't. We suspect this might be the case because of the error messages:
/bin/sh: 1: set: Illegal option -o pipefail
Here we see that /bin/sh (the shell) is being invoked by the program. Use ls -l /bin/sh to determine if your /bin/sh is pointing to a particular shell. If it is not pointed to a bash shell, then you either need to repoint it (be careful! this is probably another question in it's own right), or need to specify to your Scala program to use a specific shell.

Why am I getting if: Expression Syntax when I try to run this script?

I am currently trying to run a Unix Executable File in terminal (my shell is TCSH) I downloaded online and I keep getting the following error:
if: Expression Syntax
Here is the script I am trying to run:
if [ -f .1 ]
then
cc -o xrdcalc .source/xrdcalc-1.1.c -lm
chmod 700 xrdcalc
./xrdcalc
else
platform=`uname`
echo
echo
echo "You are using \"xrdcalc\" for the first time on $platform , read the \"Readme.txt\" file and then proceed"
echo
echo
echo "Press enter...."
read char;
echo `date` > .1
mkdir .source
mv xrdcalc-1.1.c .source
cc -o xrdcalc .source/xrdcalc-1.1.c -lm
./xrdcalc
fi
I have little experience with running scripts and I am sure it is an easy fix.
There are other issues with this code that indicate it was coded for traditional sh or bash.
Just put #!/bin/bash as the first line (using the correct path to your system's copy of bash), and it should work without other modifications.
Of course,
chmod 755 scriptName
is also required to "mark" the file as executable and if the file is saved to a directory not in the path, you need to either cd to the correct dir, or invoke as
/full/path/to/scriptName
If you're using a reduced version of Linux that doesn't have bash installed and you can't install it for some reason, then look for other 'Bourne Shell' derived shell processors, like ash, dash, ksh, sh .
IHTH

Resources