I have a script on a remote machine. I SSH in and call it with zsh my-script.sh:
#!/bin/zsh
# Load some environment variables
source $HOME/.extra
send_notification() {
$HOME/bin/hass-cli service call notify.alec --arguments title="$1",message="$2"
}
# THIS WORKS
send_notification "My-Title" "My-description."
# THIS DOESN'T WORK
send_notification "My Title" "My description."
As you can see from the comments, when there's a space in a string when I pass it to send_notification function they don't get escaped properly and I get the following error from hass-cli:
Error: Got unexpected extra arguments (My Title,message=My description.)
When there's no spaces in the strings it works fine. Any ideas how I can properly escape these spaces?
There are always passed two arguments to send_notification, and the function passes the arguments on to hass-cli. Actually, the quotes around $1 and $2 are redundant, since you are using zsh, but they don't harm.
The bug therefore must be in the hass-cli program. Perhaps the arguments are not processed properly, so you have to fix this.
As coded the command becomes:
hass-cli service call notify.alec --arguments title=My Title,message=My description.
One easy solution would be to wrap the variable references in single quotes (inside the double quotes) like such:
hass-cli service call notify.alec --arguments title="'$1'",message="'$2'"
So the call becomes:
hass-cli service call notify.alec --arguments title='My Title',message='My description.'
This assumes single quotes don't have a special meaning for hass-cli, otherwise replace the single quotes with escaped double quotes:
hass-cli service call notify.alec --arguments title="\"$1\"",message="\"$2\""
So the command now becomes:
hass-cli service call notify.alec --arguments title="My Title",message="My description."
Related
Is there a way to access all the variables/arguments passed through the command line or variable file (-V option) during robotframework execution. I know in python the execution can access it with 'sys.args' feature.
The answer for getting the CLI arguments is inside your question - just look at the content of the sys.argv, you'll see everything that was passed to the executor:
${args}= Evaluate sys.argv sys
Log To Console ${args}
That'll return a list, where the executable itself (run.py) is the 1st member, and all arguments and their values present the in the order given during the execution:
['C:/my_directories/rf-venv/Lib/site-packages/robot/run.py', '--outputdir', 'logs', '--variable', 'USE_BROWSERSTACK:true', '--variable', 'IS_DEV_ENVIRONMENT:false', '--include', 'worky', 'suites\\test_file.robot']
You explicitly mention variable files; that one is a little bit trickier - the framework parses the files itself, and creates the variables according to its rules. You naturally can see them in the CLI args up there, and the other possibility is to use the built-in keyword Get Variables, which "Returns a dictionary containing all variables in the current scope." (quote from its documentation). Have in mind though that these are all variables - not only the passed on the command line, but also the ones defined in the suite/imported keywords etc.
You have Log Variables to see their names and values "at current scope".
There is no possibility to see the arguments passed to robot.
(Question already posted on Unix Forum, but didn't get any response)
I have in my .zshrc the following function definition (simplified example):
function foo {
local p=${1:?parameter missing}
echo continue ....
}
Running the function by just typing foo produces, as expected, the message parameter missing, but it also outputs continue. I had expected that the function terminates when the :? check fails, but it continues to run. Why is this the case?
The man-page zshexpn says about :?:
... otherwise, print word and exit from the shell. Interactive shells instead return to the prompt.
I found that the behaviour I am experiencing depends on the presence or absence of the local specifier. If I remove local, the function works as expected, i.e. returns from the function immediately, if no parameter is passed.
Since I need local in my application, I rewrote the function like this:
function foo {
: ${1:?parameter missing}
local p=$1
echo continue ....
}
This works fine, but I still am curious to know, why the presence of local in combination with a :? causes this difference in behaviour.
UPDATE : I posted the issue also on the Zsh mailing list, and the zsh developers confirmed that this is a bug in Zsh.
I can call ^methods on an object and list the method names I can call:
my $object = 'Camelia';
my #object_methods = $object.^methods;
#object_methods.map( { .gist } ).sort.join("\n").say;
^methods returns a list which I store in #object_methods, then later I transform that list of method thingys by calling gist on each one to get the human-sensible form of that method thingy.
But, the ^ in ^methods is an implied .HOW, as show at the end of the object documentation this should work too:
my $object = 'Camelia';
my #object_methods = $object.HOW.methods;
But, I get an error:
Too few positionals passed; expected 2 arguments but got 1
in any methods at gen/moar/m-Metamodel.nqp line 490
in block <unit> at...
And, for what it's worth, this is an awful error message for a language that's trying to be person-friendly about that sort of thing. The file m-Metamodel.nqp isn't part of my perl6 installation. It's not even something I can google because, as the path suggests, it's something that a compilation generates. And, that compilation depends on the version.
A regular method call via . passes the invocant as implicit first argument to the method. A meta-method call via .^ passes two arguments: the meta-object as invocant, and the instance as first positional argument.
For example
$obj.^can('sqrt')
is syntactic sugar for
$obj.HOW.can($obj, 'sqrt')
In your example, this would read
my #object_methods = $object.HOW.methods($object);
I'm trying to set an array in ZSH (configured using oh-my-zsh).
export AR=(localhost:1919 localhost:1918)
but I'm getting an error like such:
zsh: number expected
If I don't add the export command, it's just fine. I'm not typing the above in a *rc file, just in the zsh prompt. What could be the problem?
You can't export an array in zsh.
For more info: http://zsh.sourceforge.net/Guide/zshguide02.html
Note that you can't export arrays. If you export a parameter, then
assign an array to it, nothing will appear in the environment; you can
use the external command printenv VARNAME (again no $ because the
command needs to know the name, not the value) to check. There's a
more subtle problem with arrays, too. The export builtin is just a
special case of the builtin typeset, which defines a variable without
marking it for export to the environment. You might think you could do
typeset array=(this doesn\'t work)
but you can't --- the special
array syntax is only understood when the assignment does not follow a
command, not in normal arguments like the case here, so you have to
put the array assignment on the next line. This is a very easy mistake
to make. More uses of typeset will be described in chapter 3; they
include creating local parameters in functions, and defining special
attributes (of which the export attribute is just one) for
parameters.
I want to create my own pipeline like in Unix terminal (just to practice). It should take applications to execute in quotes like that:
pipeline "ls -l" "grep" ....
I know that I should use fork(), execl() (exec*) and API to redirect stdin and stdout. But are there any alternatives for execl to execute app with arguments using just one argument which includes application path and arguments? Is there a way not to parse manually ls -l but pass it as one argument to execl?
If you have only a single command line instead of an argument vector, let the shell do the parsing for you:
execl("/bin/sh", "sh", "-c", the_command_line, NULL);
Of course, don't let untrusted remote user input into this command line. But if you are dealing with untrusted remote user input to begin with, you should try to arrange to pass actual a list of isolated arguments to the target application as per normal usage of exec[vl], not a command line.
Realistically, you can only really use execl() when the number of arguments to the command are known at compile time. In a shell, you'll normally use execv() or execvp() instead; these can handle an arbitrary number of arguments to the command to be executed. In theory, you use execv() when the path name of the command is given and execvp() (which does a PATH-based search for the command) when it isn't. However, execvp() handles the 'path given' case, so simply use execvp().
So, for your pipeline command, you'll end up with one child using something equivalent to:
char *args_1[] = { "ls", "-l", 0 };
execvp(args_1[0], args_1);
The other child will end up using something equivalent to:
char *args_2[] = { "grep", "pattern", 0 };
execvp(args_2[0], args_2);
Except, of course, that you'll have created those strings from the command line arguments instead of by initialization as shown. Note that grep requires a pattern to search for.
You've still got plumbing issues to resolve. Make sure you close enough pipe file descriptors. When you dup() or dup2() a pipe to standard input or standard output, you close both the file descriptors from the pipe() function.