How do I update a datastore variable from inside a bash variable? - yocto

I have a variable set in a bbclass file like:
#some-class.bbclass
PROC ??= ""
In a recipe inheriting the class, I have a bash function where I modify that variable and immediately read its value. But, the value never gets updated.
#some-bb-file.bb
inherit some-class.bbclass
some_configure() {
PROC=$(grep -r "Processor.*${cpu_id}" ... something)
bbnote "PROC is ${PROC}"
}
I always get "PROC is " in the logs. I have tried printing the output of "(grep -r "Processor.*${cpu_id}" ... something)" and it returns a valid string. Can someone please tell me what I am missing?

Usage of bitbake and shell variables in your code snippet is mixed. Your bbnote line should omit the curly braces to access the shell variable, i.e.:
bbnote "PROC is $PROC"
Explanation: The bitbake and local shell variables are different. If you are in the shell function, then ${PROC} is the variable defined in some-class.bbclass. That variable isn't redefined when you do PROC="foo". If you use $PROC, the shell variable defined by PROC="foo" is used.
And your question in the title - I'm not sure if it is possible to update datastore variable from shell. You can get and set datastore variables in Python functions (using d.getVar and d.setVar).

Datastore variables can be read from Shell using :
${#d.getVar('PROC')}
In case you have to use others operations, then switch to Python

I guess you missed backticks
PROC=`grep -r "Processor.*${cpu_id}" ... something`
bbnote "PROC is ${PROC}"

Related

Powershell Variable replacement not working from command line

I have the following command I want to run from PowerShell:
docker run -v C:\src\docker_certs:/root/.dotnet/https -it MyContainer:MyTag /bin/bash
When I run that it works perfectly. (It mounts a volume using the source folder at the destination folder.)
But when I run this:
docker run -v $env:DOCKER_CERTS_PATH:/root/.dotnet/https -it MyContainer:MyTag /bin/bash
The volume does not get mounted.
I run this to check the value:
echo $env:DOCKER_CERTS_PATH
And it returns:
C:\src\docker_certs
As I understood things, it should have replaced the value of $env:DOCKER_CERTS_PATH with C:\src\docker_certs in the second command.
How can I get the PowerShell reference to an environment variable to replace when I run a command?
Enclose the environment-variable reference in {...}:
docker run -v ${env:DOCKER_CERTS_PATH}:/root/.dotnet/https ...
Alternatively, `-escape the : char. following the env.-var. reference:
docker run -v $env:DOCKER_CERTS_PATH`:/root/.dotnet/https ...
As for what you tried:
docker run -v $env:DOCKER_CERTS_PATH:/root/.dotnet/https ...
If you don't use {...} to explicitly delineate a variable name, PowerShell may have a different idea of where the variable name ends than you do.
As an alternative to using {...}, you can `-escape the first character you don't want to be considered part of the variable name.
Note that your command argument is in this case implicitly treated as if it were enclosed in "...", so the above applies to expandable strings ("...") too.
For an comprehensive discussion of how unquoted tokens are parsed as command arguments, see this answer.
In the case at hand, the : that follows $env:DOCKER_CERTS_PATH is not considered the end of the variable reference; instead, it is considered part of the variable name, so that PowerShell looks for an environment variable (env:) literally named DOCKER_CERTS_PATH: (sic).
Since no such environment variable (presumably) exists, $env:DOCKER_CERTS_PATH: expands to the empty string and all that is passed to docker is /root/.dotnet/https.
You can verify that DOCKER_CERTS_PATH: is a valid environment variable name as follows:
PS> $env:DOCKER_CERTS_PATH: = 'hi'; $env:DOCKER_CERTS_PATH:
hi
By contrast, a regular (shell) variable is not permitted to contain :, because that : - in the absence of a namespace prefix such as env: - is itself considered a namespace prefix, which fails, because then the variable-name part is missing:
PS> $DOCKER_CERTS_PATH: = 'hi' # BREAKS, even with {...}
Variable reference is not valid. ':' was not followed by a valid variable name character. Consider using ${} to delimit the name.
The first : in a variable identifier is invariably considered the end of the namespace identifier, which must refer to an existing PowerShell drive name, as reported by Get-PSDrive.
This notation is called namespace variable notation, as explained in this answer.

Read command output line by line in sh (no bash)

I am basically looking for a way to do this
list=$(command)
while read -r arg
do
...
done <<< "$list"
Using sh intead of bash. The code as it is doesn't run because of the last line:
syntax error: unexpected redirection
Any fixes?
Edit: I need to edit variables and access them outside the loop, so using | is not acceptable (as it creates a sub-shell with independent scope)
Edit 2: This question is NOT similar to Why does my Bash counter reset after while loop as I am not using | (as I just noticed in the last edit). I am asking for another way of achiving it. (The answers to the linked question only explain why the problem happens but do not provide any solutions that work with sh (no bash).
There's no purely syntactic way to do this in POSIX sh. You'll need to use either a temporary file for the output of the command, or a named pipe.
mkfifo output
command > output &
while read -r arg; do
...
done < output
rm output
Any reason you can't do this? Should work .. unless you are assigning any variables inside the loop that you want visible when it's done.
command |
while read -r arg
do
...
done

How to set environment variables for a shell command

I often see this command in node.js programs: NODE_ENV=test node app.js which sets the NODE_ENV variable to test and works. I also read here https://en.wikipedia.org/wiki/Environment_variable that this should work for any shell command, but running some tests on my own, here is what I see
$ HELLO="WORLD"
$ HELLO="MARS" echo "$HELLO"
WORLD
$
I would expect this to print MARS. Is there something I am missing here?
The syntax VAR=value command means that the command will be invoked with the environment variable VAR set to VALUE, and this will apply only for the scope of that command.
However, when you are using the command line:
HELLO="MARS" echo "$HELLO"
The shell first interprets the "$HELLO" parameter, determines that it is WORLD, and then what it actually does is run:
HELLO="MARS" echo "WORLD"
So the echo may have the HELLO variable set, but it doesn't affect what it prints - it has already been interpreted before.
Doing
HELLO="MARS"; echo "$HELLO"
does something else entirely. First it sets HELLO to MARS in the current shell, and then it goes on to interpret the echo command. By this time HELLO contains MARS, not WORLD. But this is an entirely different effect - the variable HELLO stays with the value MARS, which is not the case in the command without the ;.
Your problem is that echo is just a poor choice for a demonstartion of this. You can do other demonstrations to prove that HELLO is changed properly:
HELLO="MARS" eval 'echo $HELLO'
In this case, the shell will not interpret the $HELLO because it is within a string in single quotes. It will first put MARS in HELLO, and then call the eval 'echo $HELLO' with that variable set. The eval command with then run echo $HELLO, and you'll get the output you were expecting.
This syntax is best used for things that don't use the given variable as part of the command line, but rather use it internally.
Other answers are correct, but here a refinement :
There are 2 cases in fact when defining a list of variable separated by spaces in bash whether it ends or not with a command.
VAR1=value1 VAR2=value2 ... VARn=valuen command arg1 arg2 ... argn
and
VAR1=value1 VAR2=value2 ... VARn=valuen
don't export VAR1 ... VARn the same way.
In first case VAR1 ... VARn will be set only for command and will then not be exported to current shell.
In second case VAR1 ... VARn will alter current shell.
then ( remark that ';' is very same of using a new line )
HELLO=WORLD
HELLO=MARS echo "i don't export HELLO."
echo "HELLO=$HELLO"
will display
i don't export HELLO.
HELLO=WORLD
and
HELLO=WORLD
HELLO=MARS ; echo "i did export HELLO."
echo "HELLO=$HELLO"
will display
i did export HELLO.
HELLO=MARS

Pipe output to environment variable export command

I'm trying to set a git hash value into an environment variable, i thought it would be as simple as doing this:
git log --oneline -1 | export GIT_HASH=$1
But the $1 doesn't contain anything. What am I doing wrong?
$1 is used to access the first argument in a script or a function. It is not used to access output from an earlier command in a pipeline.
You can use command substitution to get the output of the git command into an environment variable like this:
GIT_HASH=`git log --oneline -1` && export GIT_HASH
However...
This answer is specially in response to the question regarding the Bourne Shell and it is the most widely supported. Your shell (e.g. GNU Bash) will most likely support the $() syntax and so you should also consider Michael Rush's answer.
But some shells, like tcsh, do not support the $() syntax and so if you're writing a shell script to be as bulletproof as possible for the greatest number of systems then you should use the `` syntax despite the limitations.
Or, you can also do it using $(). (see What is the benefit of using $() instead of backticks shell scripts?)
For example:
export FOO_BACKWARDS=$(echo 'foo' | rev)
You can use an external file as a temporary variable:
TMPFILE=/var/tmp/mark-unsworth-bashvar-1
git log --oneline -1 >$TMPFILE; export GIT_HASH=$(cat $TMPFILE); rm $TMPFILE
echo GIT_HASH is $GIT_HASH

Why doesn't shell %variable% work when set from PowerShell?

I am inserting a variable string in my PATH variable. I set the variables in following manner:
$var="MyTestPath"
$mypath=[environment]::GetEnvironmentVariable("PATH",[system.environmentvariabletarget]::User)
[environment]::SetEnvironmentVariable("TEST",$var,[system.environmentvariabletarget]::User)
[environment]::SetEnvironmentVariable("PATH",$mypath+";%TEST%",[system.environmentvariabletarget]::User)
The above code doesn't work for me. %TEST% variable doesn't expand itself when I check the path in the new shell. It shows new path ending with %TEST%. This has always worked when I set this from GUI or from Windows shell prompt. Why is this behavior different when variables are set from PowerShell? Is this feature removed in PowerShell?
I don't want to do the following, because it will keep adding my variable to path everytime I run the script.
[environment]::SetEnvironmentVariable("PATH",$mypath+";"+$var,[system.environmentvariabletarget]::User)
Try change this line:
[environment]::SetEnvironmentVariable("PATH",$mypath+";%TEST%",[system.environmentvariabletarget]::User)
with:
$test =[environment]::GetEnvironmentVariable("test","user") # this retrieve the rigth variable value
[environment]::SetEnvironmentVariable("PATH", $mypath +";$test",[system.environmentvariabletarget]::User)
%test% have no meaning in powershell, can't be expandend as in CMD.
$env:test retrive only from system environment variable and not from user
You're wanting to effectively set a registry value (that corresponds to a env var) that uses REG_EXPAND_SZ. See this post for details on how to do that.