One of my recipes in Yocto need to create a file containing a very specific line, something like:
${libdir}/something
To do this, I have the recipe task:
do_install() {
echo '${libdir}/something' >/path/to/my/file
}
Keeping in mind that I want that string exactly as shown, I can't figure out how to escape it to prevent bitbake from substituting in its own value of libdir.
I originally thought the echo command with single quotes would do the trick (as it does in the bash shell) but bitbake must be interpreting the line before passing it to the shell. I've also tried escaping it both with $$ and \$ to no avail.
I can find nothing in the bitbake doco about preventing variable expansion, just stuff to do with immediate, deferred and Python expansions.
What do I need to do to get that string into the file as is?
Bitbake seems to have particular issues in preventing expansion from taking place. Regardless of whether you use single or double quotes, it appears that the variables will be expanded before being passed to the shell.
Hence, if you want them to not be expanded, you need to effectively hide them from BitBake, and this can be done with something like:
echo -e '\x24{libdir}/something' >/path/to/my/file
This uses the hexadecimal version of $ so that BitBake does not recognise it as a variable to be expanded.
You do need to ensure you're running the correct echo command however. Under some distros (like Ubuntu), it might run the sh-internal echo which does not recognise the -e option. In order to get around that, you may have to run the variant of echo that lives on the file system (and that does recognise that option):
/bin/echo -e '\x24{libdir}/something' >/path/to/my/file
By default this task will be executed as shell function via /bin/sh, but it depends on your system what it will be as you can have a symlink named /bin/sh pointing to bash. The BitBake's manual prevents from using bashism syntax though.
You can consider just adding this task in your recipe as python function:
python do_install () {
with open('/path/to/your/file', 'a') as file:
file.write('${libdir}/something')
}
'a' stands for append.
This should eliminate the problem with variable expansion.
There is no standard way to escape these sorts of expressions that I am aware of, other than to try to break up the expression - accordingly this should work:
do_install() {
echo '$''{libdir}/something' >/path/to/my/file
}
The best solution is simply this:
bitbake_function() {
command $libdir/whatever
}
Bitbake will only expand ${libdir}; $libdir is passed through verbatim.
We don't have to worry about dollar signs that are not followed by {, and in this case, there is no need for libdir to be wrapped in braces.
The only time we run into a problem with just $foo is if we have something like ${foo}bar where the braces are required as delimiters so that bar isn't included into the variable name. In that situation, there are other solutions, such as for instance generating the shell syntax "$foo"bar. This is less cryptic than resorting to \x24.
If you need to use $ in variable assignment, remember that bitbake won't evaluate $whatever so you have to escape it for the underlying shell.
For instance I set gcc/ld Rpath option to use $ORIGIN keyword this way:
TARGET_LDFLAGS_append = " -Wl,-rpath-link=\\$$ORIGIN"
https://lists.yoctoproject.org/pipermail/yocto/2017-September/037820.html
You can define a variable to be a literal dollar sign.
DOLLAR = "$"
do_install() {
echo '${DOLLAR}{libdir}/something' >/path/to/my/file
}
no extra quoting required.
I want to add a global aliash in zsh which will look something like this:
alias -g t='> tmp-$(date +%Y%m%d-%h%m%s).txt'
What it should do is create a new timestamped temporary file in the current directory and redirect output to that file. However, the filename gets evaluated at the time of zsh being sourced instead of the alias being called.
I guess what I need is some sort of lazy evaluation. Is there a way to achieve this?
Okay, I figured out a way. More involved than I wanted it to be:
function redirect-to-tmp() {
TMPFILE="./tmp-$(date +%y%m%d-%H%M%S)"
cat >>! $TMPFILE
echo "Redirected to $TMPFILE"
}
function redirect-to-tee() {
TMPFILE="./tmp-$(date +%y%m%d-%H%M%S)"
tee -a $TMPFILE
echo "Redirected to $TMPFILE"
}
alias -g t='| redirect-to-tmp'
alias -g T='| redirect-to-tee'
Let me know if anyone else has a better answer.
I use tcsh shell and I cannot change to another shell.
I'm trying to create an alias to quickly cd into my project.
My home directory looks like:
/home/projects/proj1
/home/projects/proj2
...
/home/stuff/stuff1
If i am working in stuff 1 directory and want to quickly navigate to my projects, i created an alias as follows:
alias P 'cd /home/projects && cd ./\!:1'
so that I can type 'P proj1' to get there
However, sometimes i want to navigate to /home/projects directory instead of a particular project and i thought just typing 'P' (without arguments) will get me there but i'm getting a "Bad ! arg selector". How do i create an aliases to handle zero or more arguments?
Thanks
This works:
alias P 'cd /home/projects/\!*'
If you pass an argument, it is appended to the end of the path, else !* is replaced by nothing.
i.e. I have an alias in my .cshrc file
alias foo = /Users/name/documents
and i want to do something like
mv foobar.txt foo
but this just renames foobar.txt to foo.
Also tried
mv footbar.txt $foo
to no avail.
I think I can create a script to take in a path and filename and alias instead to the script, but is there another way to do this?
I'm working on a script that processes a folder and there is always one file in it I need to rename. The new name should be the parent directory name. How do I get this in a batch file? The full path to the dir is known.
It is not very clear how the script is supposed to become acquainted with the path in question, but the following example should at least give you an idea of how to proceed:
FOR %%D IN ("%CD%") DO SET "DirName=%%~nxD"
ECHO %DirName%
This script gets the path from the CD variable and extracts the name only from it to DirName.
You can use basename command:
FULLPATH=/the/full/path/is/known
JUSTTHENAME=$(basename "$FULLPATH")
You can use built-in bash tricks:
FULLPATH=/the/full/path/is/known
JUSTTHENAME=${FULLPATH##*/}
Explanations:
first # means 'remove the pattern from the begining'
second # means 'remove the longer possible pattern'
*/ is the pattern
Using built-in bash avoid to call an external command (i.e. basename) therefore this optimises you script. However the script is less portable.