How to setup completion of environment variable names in zsh? - environment-variables

In bash when I try to use autocompletion in double-quoted strings it works:
E.g.
echo "My home directory is $HO<t>"
# expands to
echo "My home directory is $HOME"
But when I try the same thing in zsh it just does nothing.
At the same time it works outside strings:
echo My\ home\ directory\ is\ $HO<t>
# expands to
echo My\ home\ directory\ is\ $HOME
Is it possible to make it work the same as bash?

Zsh completion has a bug where completion of parameter names fails if a partial parameter name is followed by a ".
As a workaround, just remove the final " from your string before pressing Tab. Then, Zsh's completion will work correctly and it will automatically add the final " for you.

Related

How to use paths with spaces in automator shell script?

I have an Automator workflow which should set the CreationDate of the selected file to a date which I want to enter. Unfortunately my path have spaces. Therefore it doesn'w work.
I've tried several variants like:
SetFile -d \"$1 12:00:00\" "$#2"
SetFile -d \"$1 12:00:00\" \"$#2\"
SetFile -d \"$1 12:00:00\" '$#2'
SetFile -d \"$1 12:00:00\" \'$#2\'
The path is like follows:
/Users/simon/Documents/Steuern/Steuern 2021/Scan_000775.pdf
The shell I use is ZSH with oh-my-zsh installed.
This is the Workflow I have:
Ask for Finder-Object
Get value of variable
Ask for Text input
Set value of variable
Ask for value of variable
execute shell script: "SetFile -d "$1 12:00:00" "$#2""
Can anyone tell me how to write the shellscript to use pathnames with spaces?
That would be very nice. Thank you.
If I'm understanding right, you want:
SetFile -d "$1 12:00:00" "${#:2}"
Explanation: escaping quotes prevents them from acting like quotes (it turns them into normal characters); in this case, you want them to function as quotes, so you shouldn't escape them. Also, "$#2" doesn't get the arguments starting at $2, it gets all of the arguments, and sticks a "2" to the end of the last one. If you want all the arguments except the first, use "${#:2}" instead.

How to get input from user and use it in CMD using DXL?

Hello I have been trying to get user input and store it in a variable, and then use that variable in a CMD. ALL of this in a DXL script!
Take a glance into the code I have tried this but still not working.
string wheretosave = ""
DB exBox = create "Get Path"
DBE stringInn = field(exBox, "ADD Path where to save:", "", 80)
void doGet(DB exBox) {
wheretosave = get stringInn
print wheretosave "\n"
system("cmd.exe /C cd /d wheretosave & dir & PAUSE")
}
apply(exBox, "Get", doGet)
show exBox
to add "wheretosave" to a string, use
system("cmd.exe /C cd /d " wheretosave " & dir & PAUSE")
But I think the system call does not work. When I start a command line and do a command
cmd.exe /C cd /d d:\temp & dir & PAUSE
then I get the dir of the original directory.
#root: ADDITION: my problem was that I did not have a directory d:\temp on my PC...
But after reading your comment, it seems the point was not understood.
To be more precise:
First: there is no interpolation in DXL. If you want to create a string which contains a) some fixed characters, b) the content of a variable (here: wheretosave) and c) some more fixed characters, you have to use a < space > to concanate the three parts. So, do it like this: string s1 = "fixedtexta" wheretosave "fixedtextb".
Second: If the fixed characters contains a quotation mark then you have to escape it with a backslash. So, this example would become to string s2 = "fixedtexta\"" wheretosave "\"fixedtextb" to get fixedtexta"hello world"fixedtextb if wheretosavecontains hello world
BUT your example is even more difficult.
Third: cmd.exe /C takes only one parameter. So, if you want to do more than one command in the cmd subshell, you have to surround all the commands with enclosing quotation marks cmd.exe /C "cmd 1 & cmd 2 & cmd 3" The way you wrote it would have translated to
create a subshell which does a "cd /d", end the subshell
in the main shell (which is still in the original directory), do a "dir"
in the main shell, do a "pause"
Fourth: In DOS, if you have a quotation mark inside a string, you have to escape it with a second quotation mark.
All in all the command you are looking for is
string wheretosave = "d:\\temp x" // or get stringInn in your example
system("cmd.exe /C \"cd /d \"\"" wheretosave "\"\" & dir & pause\"")
Try providing the full path and apply Mike's correction. Using "C:\Windows" works as expected (for me): the cmd shows the content of my Windows folder on drive C.

How to escape a $-sign in a dockerfile?

I am trying to write a dockerfile in which I add a few java-options to a script called envvars.
To achieve that I want to append a few text-lines to said file like so:
RUN echo "JAVA_OPTS=$JAVA_OPTS -Djavax.net.ssl.trustStore=${CERT_DIR}/${HOSTNAME}_truststore.jks" >> ${BIN_DIR}/envvars
RUN echo "JAVA_OPTS=$JAVA_OPTS -Djavax.net.ssl.trustStorePassword=${PWD_TRUSTSTORE}" >> ${BIN_DIR}/envvars
RUN echo "export JAVA_OPTS" >> ${BIN_DIR}/envvars
The issue here is, that I want the misc. placeholders ${varname} (those with curly braces) to be replaced during execution of the docker build command while the substring '$JAVA_OPTS' (i.e. those without braces) should be echoed and thus added to the envvars file verbatim, i.e. in the end the result in the /usr/local/apache2/bin/envvars file should read:
...
JAVA_OPTS=$JAVA_OPTS -Djavax.net.ssl.trustStore=/usr/local/apache2/cert/myserver_truststore.jks
JAVA_OPTS=$JAVA_OPTS -Djavax.net.ssl.trustStorePassword=my_secret
export JAVA_OPTS
How can one escape a $-sign from variable substitution in dockerfiles?
I found hints to use \$ or $$ but neither worked for me.
In case that matters (which I hope/expect not to): I am building the image using "Docker Desktop" on Windows 10 but I would expect the dockerfile to be agnostic of that.
first you need to add this # escape=` to your Dockerfile since \ is an escape charachter in the Dockerfile . then you can use \$ to escape the dollar sign in the RUN section
Example:
# escape=`
RUN echo "JAVA_OPTS=\$JAVA_OPTS -Djavax.net.ssl.trustStore=${CERT_DIR}/${HOSTNAME}_truststore.jks" >> ${BIN_DIR}/envvars
that will be JAVA_OPTS=$JAVA_OPTS in your env file

Error when trying to use variables in the post build event with delphi 10.2

I use windows 7 pro service pack 1.
I have the following code in the post build event :
SET VAR1=BLABLA
ECHO %VAR1% > Test.txt
It wont work. In the file, i get «command echo activated» (translated from french).
Embarcadero documentation says that i can use any valid dos command in those events.
If i just use :
ECHO BLABLA > Test.txt
It works, no problem. Is this a bug or there is a problem with % character ? % is an ascii char so i dont even know what could be the problem.
ty for your help.
% is used in cmd to delimit variablenames when the value of the variable is required, hence echo %var1% > test.txt will write the current value of the environment variable var1 to the file.
If var1 is not defined at the time, it will report the echo status (Echo is on/off`.
This can be circumvented by using echo(%var1% - the ( modifies echo's behaviour to not report the echo status if the arguments are resolved to nothing.
If you want to echo a literal % then you need to escape the % with another %. cmd normally uses ^ to escape symbols with a special meaning - % is the exception; %% to echo a literal %.
BTW - the space between the string to be echoed and the redirector will be output to the file. To prevent this, use > test.txt echo %var1% Note that > creates a file anew. >> will create or append if the file already exists. The space between the redirector and the filename is optional.
However, it's important when using batch to post exactly the code that's in use.
SET VAR1=BLABLA
ECHO %VAR1% > Test.txt
will work happily.
SET VAR1 = BLABLA
ECHO %VAR1% > Test.txt
will not because this latter code sets a variable named "var1Space"
On my 10.2.1 system, I've tried the code as published.
The actual code that's executed is
SET VAR1=BLABLA&ECHO %VAR1% > Test.txt
not
SET VAR1=BLABLA
ECHO %VAR1% > Test.txt
as shown in the "Build events commands" window.
This will not work because the entire line is executed as published on the "build events" page - SET VAR1=BLABLA&ECHO %VAR1% > Test.txt which will be interpreted by cmd after cmd performs its standard parsing routine.
cmd replaces any %var% with the actual value at parse time, not at run time hence as var1 has no value when the line SET VAR1=BLABLA&ECHO %VAR1% > Test.txt is parsed, the code is executed as SET VAR1=BLABLA&ECHO > Test.txt hence the problem encountered.
To cure this, you need to use
SET VAR1=BLABLA&call ECHO %%VAR1%% > Test.txt
where cmd will execute the parsed-ECHO command in a subshell. % is the escape character for % so the subshell executes ECHO %VAR1% > Test.txt after var1 has been set.
I'd suggest you raise this as a problem with EMBT. Batch commands cannot be strung together with & without side-effects. The code entered into the "Build events commands" window should be executed without reformatting - just written to a (temporary) batch file and the batch file then executed.
No doubt the eager downvoters will support the resolution of this problem.

How can I tell from a within a shell script if the shell that invoked it is an interactive shell?

I'm trying to set up a shell script that will start a screen session (or rejoin an existing one) only if it is invoked from an interactive shell. The solution I have seen is to check if $- contains the letter "i":
#!/bin/sh -e
echo "Testing interactivity..."
echo 'Current value of $- = '"$-"
if [ `echo \$- | grep -qs i` ]; then
echo interactive;
else
echo noninteractive;
fi
However, this fails, because the script is run by a new noninteractive shell, invoked as a result of the #!/bin/sh at the top. If I source the script instead of running it, it works as desired, but that's an ugly hack. I'd rather have it work when I run it.
So how can I test for interactivity within a script?
Give this a try and see if it does what you're looking for:
#!/bin/sh
if [ $_ != $0 ]
then
echo interactive;
else
echo noninteractive;
fi
The underscore ($_) expands to the absolute pathname used to invoke the script. The zero ($0) expands to the name of the script. If they're different then the script was invoked from an interactive shell. In Bash, subsequent expansion of $_ gives the expanded argument to the previous command (it might be a good idea to save the value of $_ in another variable in order to preserve it).
From man bash:
0 Expands to the name of the shell or shell script. This is set
at shell initialization. If bash is invoked with a file of com‐
mands, $0 is set to the name of that file. If bash is started
with the -c option, then $0 is set to the first argument after
the string to be executed, if one is present. Otherwise, it is
set to the file name used to invoke bash, as given by argument
zero.
_ At shell startup, set to the absolute pathname used to invoke
the shell or shell script being executed as passed in the envi‐
ronment or argument list. Subsequently, expands to the last
argument to the previous command, after expansion. Also set to
the full pathname used to invoke each command executed and
placed in the environment exported to that command. When check‐
ing mail, this parameter holds the name of the mail file cur‐
rently being checked.
$_ may not work in every POSIX compatible sh, although it probably works in must.
$PS1 will only be set if the shell is interactive. So this should work:
if [ -z "$PS1" ]; then
echo noninteractive
else
echo interactive
fi
try tty
if tty 2>&1 |grep not ; then echo "Not a tty"; else echo "a tty"; fi
man tty :
The tty utility writes the name of the terminal attached to standard
input to standard output. The name that is written is the string
returned by ttyname(3). If the standard input is not a terminal, the
message ``not a tty'' is written.
You could try using something like...
if [[ -t 0 ]]
then
echo "Interactive...say something!"
read line
echo $line
else
echo "Not Interactive"
fi
The "-t" switch in the test field checks if the file descriptor given matches a terminal (you could also do this to stop the program if the output was going to be printed to a terminal, for example). Here it checks if the standard in of the program matches a terminal.
Simple answer: don't run those commands inside ` ` or [ ].
There is no need for either of those constructs here.
Obviously I can't be sure what you expected
[ `echo \$- | grep -qs i` ]
to be testing, but I don't think it's testing what you think it's testing.
That code will do the following:
Run echo \$- | grep -qs i inside a subshell (due to the ` `).
Capture the subshell's standard output.
Replace the original ` ` expression with a string containing that output.
Pass that string as an argument to the [ command or built-in (depending on your shell).
Produce a successful return code from [ only if that string was nonempty (assuming the string didn't look like an option to [).
Some possible problems:
The -qs options to grep should cause it to produce no output, so I'd expect [ to be testing an empty string regardless of what $- looks like.
It's also possible that the backslash is escaping the dollar sign and causing a literal 'dollar minus' (rather than the contents of a variable) to be sent to grep.
On the other hand, if you removed the [ and backticks and instead said
if echo "$-" | grep -qs i ; then
then:
your current shell would expand "$-" with the value you want to test,
echo ... | would send that to grep on its standard input,
grep would return a successful return code when that input contained the letter i,
grep would print no output, due to the -qs flags, and
the if statement would use grep's return code to decide which branch to take.
Also:
no backticks would replace any commands with the output produced when they were run, and
no [ command would try to replace the return code of grep with some return code that it had tried to reconstruct by itself from the output produced by grep.
For more on how to use the if command, see this section of the excellent BashGuide.
If you want to test the value of $- without forking an external process (e.g. grep) then you can use the following technique:
if [ "${-%i*}" != "$-" ]
then
echo Interactive shell
else
echo Not an interactive shell
fi
This deletes any match for i* from the value of $- then checks to see if this made any difference.
(The ${parameter/from/to} construct (e.g. [ "${-//[!i]/}" = "i" ] is true iff interactive) can be used in Bash scripts but is not present in Dash, which is /bin/sh on Debian and Ubuntu systems.)

Resources