variable assignment of Makefile - makefile

I saw the question:
makefile-variable-assignment
then I did as below:
HELLO='hello 1st'
HELLO_WORLD='$(HELLO) world!'
HELLO='hello 2nd'
all :
echo $(HELLO_WORLD)
HELLO='hello 3rd'
echo $(HELLO_WORLD)
HELLO='hello 4th'
echo $(HELLO_WORLD)
the result is that:
root#ubuntu:~# make all -s
hello 2nd world!
hello 2nd world!
hello 2nd world!
I confused, why the value of 'HELLO' was not set to hello 4th but hello 2nd
update:
I update my code :
HELLO='hello 1st'
HELLO_WORLD='$(HELLO) world!'
HELLO='hello 2nd'
all :
HELLO='hello 3rd' && echo $(HELLO_WORLD)
HELLO='hello 4th' && echo $(HELLO_WORLD)
And the result:
root#ubuntu:~# make all -s
hello 2nd world!
hello 2nd world!
I have realized the sentences like HELLO='hello 3rd' is not variable assignments finally.
You two help me a lot. Thanks the answers!

The lines like
HELLO='hello 3rd'
are not (make) variable assignments, but lines in the rule action.
The relevant section of the make manual says that the variable has to be at the start of the line.
As you've written it, the HELLO=... lines are simply action lines. In these cases, the command HELLO='hello 3rd' sets the shell variable HELLO in a new shell, which then immediately exits (as the answer form #sergei-kurenkov mentions, each line is executed in a different shell).

why the terminal print not hello 4th world but hello 2nd world
Each line in recipes is executed in its own shell. So after you have uncommented 4 lines the for the target 'all' you run shell 5 times and enviroment variables in set in first run will not be seen in the second run and so forth.
Source: http://www.gnu.org/software/make/manual/html_node/Execution.html#Execution

Related

what does prefixed exclamation mark (`!`) command mean/do in shell?

We usually use $ as prompt in code block to demonstrate shell commands:
$ echo "hello world" > foo.md
$ cat foo.md
hello world
The problem is that you can't copy and paste those two lines with prefixed $ into your Terminal and execute them.
bash: $: command not found
However, I accidentally found that you can use prefixed ! for your commands (and prefixed # for outputs as comments)
! echo "hello world" > foo.md
! cat foo.md
# hello world
! ls
Now you can copy and paste above 4 lines into your shell and execute them at once.
Is that true? Is it worth to use ! for demonstration within code blocks in markdown files?
What does prefixed exclamation mark (!) command mean/do in shell?
As #chepner mentions below, the standalone ! is acting as a logical not operator.
Beyond that, traditionally the $ prefix indicates that the command should be run as an unprivileged user and the # prefix indicates that the command should run as a privileged user (root). See this answer for some more info.

How can we output the results of a script to a csv file? [duplicate]

I am trying to have a for loop output a text to a file 10 times. Here is what I have:
for ((i=1;i<=10;i++)); do
echo "Hello World" >testforloop.txt
done
This outputs Hello World once to the file testforloop.txt. If I don't output to file it prints Hello World to the screen 10 times.
You are using > redirection, which wipes out the existing contents of the file and replaces it with the command's output, inside the loop. So this wipes out the previous contents 10 times, replacing it with one line each time.
Without the >, or with >/dev/tty, it goes to your display, where > cannot wipe anything out so you see all ten copies.
You could use >>, which will still open the file ten times, but will append (not wipe out previous contents) each time. That's not terribly efficient though, and it retains data from a previous run (which may or may not be what you want).
Or, you can redirect the entire loop once:
for ... do cmd; done >file
which runs the entire loop with output redirected, creating (or, with >>, opening for append) only once.
You're only redirecting the echo with ">", so it overwrites. What you need is to append using ">>" operator. Do the following:
for ((i=1;i<=10;i++)) ; do echo "Hello World" >> testforloop.txt ; done
The following will solve your problem:
You should try the >> operator for the reasons already mentioned with the command echo -e
Using option ‘\n‘ – New line with backspace interpretor ‘-e‘ treats
new line from where it is used.
link
Doing so:
for ((i=1;i<=10;i++)) ; do echo -e "Hello World" >> testforloop.txt ; done
cat command:
cat testforloop.txt
output:
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Alternatively, you can try:
cat -n testforloop.txt
output:
1 Hello World
2 Hello World
3 Hello World
4 Hello World
5 Hello World
6 Hello World
7 Hello World
8 Hello World
9 Hello World
10 Hello World
You rewrite the testforloop.txt ten times. If you did
for ((i=1;i<=10;i++)) ; do echo "Hello World" > testforloop(i).txt ; done
where i is the int from the for loop. I'm not sure the language you're programming in.

Why do alias foo1="echo $1" and alias foo2="echo '$1'" behave as they do?

In my .bashrc file, I put the following two lines:
alias foo1="echo $1"
alias foo2="echo '$1'"
Then, in the terminal, I get the following output:
$ foo1 hello world
hello world
$ foo2 hello world
hello world
Why is the extra space produced by foo2?
If I just do the following in terminal, the outputs are as shown:
$ echo hello world
hello world
$ echo 'hello world'
hello world
This leads me to think that foo1 and foo2 should do exactly the same thing. How come they do not actually output exactly the same thing, and why do they differ by simply one space character?
(Also, why do either of them output world? I would expect only the first argument to be outputted.)
If, in a typical interactive shell, you run:
$ set -- # this clears the argument list; it's empty by default, but make sure.
$ alias foo1="echo $1"
$ alias foo2="echo '$1'"
$ alias -p
The output of alias -p is as follows:
$ alias -p
alias foo1='echo '
alias foo2='echo '\'''\'''
Notably, the $1s are not present at all -- because you defined the alias in a double-quoted string, they were replaced with the current value of $1 -- the value present in the current shell's context, which for an interactive shell is going to be empty at startup.
Thus, when you run:
foo2 hello world
...what the shell invokes is:
echo '' hello world
Because echo puts spaces between its arguments, this prints out as:
hello world
Whereas, if you run:
foo1 hello world
...what the shell invokes is:
echo hello world
...because, as you can see in the foo1 alias emitted by alias -p, there is no record of the unquoted $1 left; it was replaced with its current value -- an empty string -- at definition time.
aliases do not take positional arguments. $1 will evaluate to nothing inside an alias. foo2 is literally appending what you typed after foo2 to the empty string '', which includes the space after foo2. foo1 is not appending to anything as $1 evaluates to nothing, so the space is not shown.

What is the difference beetwen $ echo Hello world > file and $ echo Hello > file world in bash?

$ echo Hello world > file
$ echo Hello > file world
$ echo > file Hello world
$ > file echo Hello world
They all do the same thing, but I do not know why.
From man bash:
Simple Commands
A simple command is a sequence of optional variable assignments fol-
lowed by blank-separated words and redirections, and terminated by a
control operator. The first word specifies the command to be executed,
and is passed as argument zero. The remaining words are passed as
arguments to the invoked command.
That is, it doesn't specify the ordering of the "words and redirections".
Later in the REDIRECTIONS section:
REDIRECTION
[...]
The [...] redirection opera-
tors may precede or appear anywhere within a simple command or may fol-
low a command. Redirections are processed in the order they appear,
from left to right.
[...]
So they can appear anywhere.
And as you yourself have observed too, there's no difference between them in terms of the result.
There is a difference however in readability.
This is the most intuitive way of writing it:
echo Hello world > file
Really easy to understand. The > looks like an arrow, doesn't it.
The others are not so intuitive, less readable.
I suggest to stick to the first writing style.

How to run a command from a variable in shell scripting

How to run a command after assigning it to some variable in shell scripting?
example:
command_name=echo
Now, is there a way to use "$command_name hello world" instead of "echo hello world" ?
Yes. That exact code ($command_name hello world) will work.
Make sure that quotes, if present, are placed only around the command name and each individual argument. If quotes are placed around the entire string, it will interpret the entire string as the command name, which isn't what you want.
For example:
command_name="echo"
$command_name hello world
will be interpreted as:
echo hello world
(which works), whereas:
command_name="echo"
"$command_name hello world"
is interpreted as:
"echo hello world"
which doesn't work because it's trying to find a command called echo hello world rather than interpreting hello and world as arguments.
Similarly,
command_name="echo hello world"
"$command_name"
fails for the same reason, whereas:
command_name="echo hello world"
$command_name
works.
command_name='echo'
$command_name "Hello World"
#!/bin/bash
var="command"
"$var"
worked for me in script file
You can use eval for this:
Suppose you have an input_file that has the following:
a b c d e f g
Now try in your terminal:
# this sed command coalesces white spaces
text='sed "s/ \+/ /g" input_file'
echo $text
sed "s/ \+/ /g" input_file
eval $text
a b c d e f g
With bash arrays (which is the best practice when you have arguments):
commandline=( "echo" "Hello world" )
"${commandline[#]}"

Resources