pipe after colon in makefile: /home/.ssh/config: | /home/.ssh [duplicate] - makefile

This question already has an answer here:
What does $$# and the pipe symbol in Makefile stand for?
(1 answer)
Closed 2 years ago.
what does | mean in the following piece of makefile?
/home/.ssh:
install -d -m 700 /home/.ssh
/home/.ssh/config: | /home/.ssh
echo "$$CONFIG" >> $#
/home/.ssh/credentials: | /home/.ssh
echo "$$CREDENTIALS" >> $#
thanks

The pipe character declares the relationship to the prerequisite rule to be of an order-only¹ type. Here, if /home/.ssh did not exist, it would be created in any case, but if its timestamp changes, none of the other things will happen just because of that.
¹: https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html

Related

Head command deletes part of line [duplicate]

This question already has answers here:
I just assigned a variable, but echo $variable shows something else
(7 answers)
Closed 2 years ago.
I have a csv file (settings.csv) with the following data (separator is a space):
-n $(output_name)
--outdir “peaks/$(output_name)”
-g hs
-f AUTO
--qvalue 0.05
--extsize 200
-B
sample input output_name
sample-chip1 sample-input1 sample1
sample-chip2 sample-input2 sample2
When I call head -7 settings.csv I get this expected output:
-n $(output_name)
--outdir “peaks/$(output_name)”
-g hs
-f AUTO
--qvalue 0.05
--extsize 200
-B
Next I tried to store this output in a variable called settings with settings=$(head -7 settings.csv) and when I echo $settings I get this output:
$(output_name) --outdir “peaks/$(output_name)” -g hs -f AUTO --qvalue 0.05 --extsize 200 -B
It has deleted the -n part of the first line in the settings.csv, and I don't know why. How can I create $settings without losing -n?
The settings variable already contains the -n option you expect to be there. It’s just that the echo command interprets it as its own (echo’s) option.
One way to avoid this problem is to quote the argument:
echo "$settings"
Alternatively, you can use
printf '%s\n' "$settings"

Bash script to run C++ binary N times and output average to file [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a C++ program that I've compiled, called code.cpp.
The binary file outputted is ./code.
The code outputs several lines of text, with the last line representing the wall time in seconds. So, for example:
<some_text>
<more_text>
...
<still_more_text>
0.0009072
For any given set of runtime flags, I would like to create a simple Bash script to run ./code with the requested flags 10 times, and then print a single line to a text file. The file should be named exactly what ./code was called as, so for example:
./code -g 12 -v 4 -m -t
Would produce a text file called ./code -g 12 -v 4 -m -t.txt, containing a single line representing the average of ten runs.
Here is the working solution I arrived at using Bash and bc:
#!/bin/bash
sum=0.0
c_command=$1
suffix=".txt"
f_name="${c_command} ${suffix}"
for n in {1..10};
do
output=$($c_command)
read -ra arr -d '' <<<"$output"
value=${arr[-1]}
sum=$(bc <<< "scale=10; $sum+$value")
done
avg=$(bc <<< "scale=10; $sum/10")
echo $avg > "${c_command}.txt"
Where the binary is called with run-time params as an argument to the script:
./script.sh "./code -g 12 -v 4 -m -t"

makefile use variable defined in target [duplicate]

This question already has answers here:
Define make variable at rule execution time
(4 answers)
Closed 4 years ago.
How can one use the variable defined inside a make target
.PHONY: foo
VAR_GLOBAL=$(shell cat /tmp/global)
foo:
echo "local" > /tmp/local
VAR_LOCAL=$(shell cat /tmp/local)
echo ${VAR_GLOBAL}
echo ${VAR_LOCAL}
here is the execution output:
$ echo global > /tmp/global
$ make foo
echo "local" > /tmp/local
VAR_LOCAL=local
echo global
global
echo
As #KelvinSherlock pointed out this is a duplicate of another question
here is the specific solution for my question:
.PHONY: foo
VAR_GLOBAL=$(shell cat /tmp/global)
foo:
echo "local" > /tmp/local
$(eval VAR_LOCAL := $(shell cat /tmp/local))
echo ${VAR_GLOBAL}
echo ${VAR_LOCAL}
You probably want to use the override directive in a target-specific variable assignment, so try:
foo: override LS_LOCAL=$(shell ls /var | tail -1)
echo ${LS_GLOBAL}
echo ${LS_LOCAL}
If LS_LOCAL is never defined (even by builtin-rules) you might not need the override keyword.
BTW, you might avoid $(shell ls /var | tail -1) by using the wildcard function combined with the lastword function (perhaps combined with notdir function), so you might code $(lastword $(wildcard /var/*)) or $(notdir $(lastword $(wildcard /var/*))) instead . However, beware of the order of expansion, and of filenames with spaces. At last the shell function probably uses your $PATH variable (so strange things could happen if some weird ls program appears there before /bin/ls). Perhaps using $(shell /bin/ls /var | /usr/bin/tail -1) might be better.
Look also into Guile-extended make; consider perhaps some other build-automation tool like ninja and/or generating your Makefile (or other build configuration) with something like a configure script generated via autoconf or cmake.
Notice also that a command in recipe can be made of several physical backslashed lines (hence executed in the same shell). Maybe you might consider something like
export MY_VAR=$$(ls /var | tail); \
dosomething; \
use $$MY_VAR
inside some recipe.

Keyword '|' in Makefile Prerequisites [duplicate]

This question already has an answer here:
What does $$# and the pipe symbol in Makefile stand for?
(1 answer)
Closed 6 years ago.
The MakeFile below:
afl-fuzz: afl-fuzz.c | test_x86
gcc afl-fuzz.c -o afl-fuzz
What's the meaning of '|' before test_x86 ?
The MakeFile is from: https://github.com/loverszhaokai/AFL/blob/gcc_mode/Makefile
targets : normal-prerequisites | order-only-prerequisites
The targets will not be updated if the order-only-prerequisites is changed.
Reference: https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html

How to use a for loop in make recipe [duplicate]

This question already has answers here:
How to use shell commands in Makefile
(2 answers)
Closed 9 months ago.
I would like to use a loop to find some files and rename them:
for i in `find $# -name *_cu.*`;do mv $i "$(echo $i|sed s/_cu//)"
done
This works in the shell. But how can I do this in a makefile recipe?
There are two main things you need to know when putting non-trivial shell fragments into make recipes:
Commands in the recipe are (of course!) executed one at a time, where command means "tab-prefixed line in the recipe", possibly spread over several makefile lines with backslashes.
So your shell fragment has to be written all on one (possibly backslashed) line. Moreover it's effectively presented to the shell as a single line (the backslashed-newlines are not plain newlines so are not used as command terminators by the shell), so must be syntactically correct as such.
Both shell variables and make variables are introduced by dollar signs ($#, $i), so you need to hide your shell variables from make by writing them as $$i. (More precisely, any dollar sign you want to be seen by the shell must be escaped from make by writing it as $$.)
Normally in a shell script you would write separate commands on separate lines, but here you effectively only get a single line so must separate the individual shell commands with semicolons instead. Putting all this together for your example produces:
foo: bar
for i in `find $# -name *_cu.*`; do mv $$i "$$(echo $$i|sed s/_cu//)"; done
or equivalently:
foo: bar
for i in `find $# -name *_cu.*`; do \
mv $$i "$$(echo $$i|sed s/_cu//)"; \
done
Notice that the latter, even though it's laid out readably on several lines, requires the same careful use of semicolons to keep the shell happy.
I found this useful, trying to use for loops to build multiple files:
PROGRAMS = foo bar other
.PHONY all
all: $(PROGRAMS)
$(PROGRAMS):
gcc -o $# $#.c
It will compile foo.c, bar.c, other.c into foor bar other executables
I spend good time on this and finally had it working. I had an easy solution using the global variable in makefile available for all targets, however I don`t want that so this is how I did it.
target:
$(eval test_cont=$(shell sh -c "docker ps | grep test" | awk '{print $$1}'))
for container in $(test_cont);do \
docker cp ssh/id_rsa.pub $${container}:/root/.ssh/authorized_keys; \
docker exec -it $${container} chown root.root /root/.ssh/authorized_keys; \
done

Resources