How to excape '&' in a sh()-call in jenkins - jenkins

I want to call curl on a webpage with get parameters from the jenkins-groovy-script via sh:
sh("curl http://example.com/page.cgi?param1=a&param2=b&param3=c")
But the command is split at the '&' and in the output log of jenkins there is something like:
+ param3=c
+ curl http://example.com/page.cgi?param1=a
+ param2=b
Of course the call to the web server only contains the first parameter.
I tried already with different kind of escaping but without success.
How can I make the call including all the parameters?

Just like in the command line, you have to quote it or escape it. Research quoting and escaping in sh shell.
Try:
sh("curl 'http://example.com/page.cgi?param1=a&param2=b&param3=c'")
sh('curl "http://example.com/page.cgi?param1=a&param2=b&param3=c"')
sh("curl http://example.com/page.cgi?param1=a\\&param2=b&param3=c")
sh("curl \"http://example.com/page.cgi?param1=a&param2=b&param3=c\"")
& in shell means to run something in the background, like sleep 10 & wait.

Related

Failed to process input: The parameter must begin with a / or -

I am running a Dockerfile but every time it stops at one point.
RUN powershell %windir%\system32\inetsrv\appcmd.exe set config /section:system.webServer/handlers /+"[name='Test',path='Test.cgi',verb='*',modules="IsapiModule",scriptProcessor="c:\Test.dll",resourceType="Unspecified", preCondition="bitness64"]"
Failed to process input: The parameter 'verb=*' must begin with a / or -
I am struggling for hours. What could be the reason?
You're trying to invoke appcmd.exe via PowerShell (powershell.exe), even though the appcmd.exe command line doesn't require the features of that shell - it seems to be composed of literal strings only.
Your use of %windir% implies that your Dockerfile uses the default shell on Windows, namely cmd.exe
Therefore, you should be able to formulate your appcmd.exe command line as you would submit it from a cmd.exe session:
RUN %windir%\system32\inetsrv\appcmd.exe set config /section:system.webServer/handlers /+[name='Test',path='Test.cgi',verb='*',modules='IsapiModule',scriptProcessor='c:\Test.dll',resourceType='Unspecified',preCondition='bitness64']
Note:
All quoting in the remainder of the argument that starts with /+ now uses only '...', for consistency; since no argument-internal " chars. are therefore in play, the need to escape them goes away.
No spaces are allowed in the remainder of the argument.
As for what you tried:
When you use the -Command / -c PowerShell CLI parameter (which is implied in the absence of -File), " characters to be passed through as part of the PowerShell command must be escaped as \".
See this answer for an explanation.
Since your /+ argument also contains embedded " chars., as part of the argument, you would have to escape them twice, namely as `\" (sic)

Powershell Docker Command Doesn't Work Like Bat File

I'm trying to create a script that starts a docker container and mounts a local folder that contains spaces in the name. I can get it to work fine when I run a *.bat file with the docker run command:
docker run -p 8081:8081 -v "C:\Test Folder With Blanks":/zzz myimage jupyter lab --notebook-dir=/zzz--ip=0.0.0.0 --port=8081 --allow-root
But when I try to do the same in a Powershell script file, I get an error:
$CMD = 'docker run -p 8081:8081 -v "C:\Test Folder With Blanks":/zzz myimage jupyter lab --notebook-dir=/zzz--ip=0.0.0.0 --port=8081 --allow-root'
Invoke-Expression $CMD
docker: invalid reference format.
See 'docker run --help'.
I'm on Win10 and running Powershell in Visual Studio Code IDE.
Thanks for ideas.
First, the obligatory warning: Unless you have a command line stored as a single string somewhere and you either fully control or trust the content of the string, Invoke-Expression should generally be avoided.
You're seeing an inconsistency in how PowerShell treats compound tokens composed of directly concatenated quoted and unquoted parts.
Specifically, argument "C:\Test Folder With Blanks":/zzz is unexpectedly broken in two, i.e passed as two arguments.
The workaround is to quote the entire argument, i.e.
"C:\Test Folder With Blanks:/zzz"
Note: I'm assuming that docker doesn't actually require partial quoting in its arguments, which it shouldn't; however, there are high-profile CLIs on Windows that do, notably msiexec.
Alternatively, use an expression enclosed in (...) to compose your string; e.g.
("C:\Test Folder With Blanks" + ':/zzz')
There's no good reason to do so in this case, but it could be helpful if you need string interpolation in one part of your string ("..."), but not in another ('...').
General caveats:
Compared to cmd.exe and also POSIX-compatible shells such as bash, PowerShell has several additional metacharacters, notably # (at the start of a token), { / }, and ;. Therefore, you cannot always expect command lines written for these shells to work as-is in PowerShell.
As of PowerShell 7.2.2, passing arguments to external programs (such as docker) is fundamentally broken with respect to arguments that have embedded " characters and empty-string arguments - see this answer.
The general pattern of the inconsistency, as of PowerShell 7.2.2, is as follows:
If an argument:
starts with a quoted token - whether single- ('...') or double-quoted ("...") -
and has additional characters directly following the closing quote,
the first such character starts a separate argument.
E.g. "foo":bar / "foo"=bar / "foo"'bar' are passed as separate arguments foo and :bar / foo and =bar / foo and bar, respectively.
In other words:
You cannot compose a single string argument from a mix of quoted and unquoted / differently quoted tokens if the first token is quoted.
Conversely, it does work if the first token is unquoted, including an unquoted simple variable reference such as $HOME.
# OK: First token is unquoted.
PS> cmd /c echo foo"bar"'baz'last
foobarbazlast
# !! BROKEN: First token is quoted.
# !! Because each successive token is quoted too,
# !! each becomes its own argument.
PS> cmd /c echo 'foo'"bar"'baz'last
foo bar baz last
GitHub issue #6467 discusses this inconsistency; however, it has been closed, because the behavior is - surprisingly - considered by design.
This does not happen if the first token is unquoted; however, there are related bugs that start with unquoted tokens that similarly break arguments in two, related to their looking like named arguments to PowerShell (which is a PowerShell concept that doesn't apply when calling external programs):
GitHub issue #11646: an argument such as -foo=1,2 breaks parsing.
GitHub issue #6291: an argument such as -foo=bar.baz is broken in two at the (first) .

use of inverted commas (" ") in sh command in jenkins file

Hi i am using scp command in jenkinsfile via sh ' '.
My command is:
sh 'sshpass -p "my-password" scp /home/jenkinshome.........'
but it fails and in console output i find that inverted commas (" ") from the command is gone.
I am not sure what is happening there. Is there any othe way to pass my password.
The solution that always works for me is I first create password less authentication between 2 servers where I want to scp. Works like a charm. No need to pass password.

SQLPlus one-line questions

I inherited some sqlplus code that no longer is valid in our Workload Automation tool. It needs to either be converted to a script and called, or a one-line command. I absolutely understand how to do the first (fairly basic). But if I wanted to convert to one line, is my thinking correct?
sqlplus -s myID/pwd <<EOF
define start_date=$start_date;
define end_date=$end_date;
define max_depth=$max_depth;
define min_units=$min_units;
#/app/myapp/sql/forecast
EOF
to convert to one line, is it as simple as:
sqlplus -s myID/pwd < define start_date=$start_date; define end_date=$end_date; define max_depth=$max_depth; define min_units=$min_units; #/app/myapp/sql/forecast
Thanks in advance
Assuming your one line is still be running from a shell script, which the call to sqlplus suggests, you can use a pipe rather than a redirect to pass the commands to SQL*Plus:
printf "define start_date=$start_date\ndefine end_date=$end_date\ndefine max_depth=$max_depth\ndefine min_units=$min_units\n#/app/myapp/sql/forecast" | sqlplus -s myID/pwd
Or perhaps slightly more readably, which you may disagree about:
printf "define start_date=%s\ndefine end_date=%d\ndefine max_depth=%d\ndefine min_units=%d\n#%s" $start_date $end_date $max_depth $min_units /app/myapp/sql/forecast | sqlplus -s myID/pwd
You need line breaks rather than semicolons to separate the define client commands from each other and the #.

Analysing a shell script

This would be part of a reverse-engineering project.
To determine and document what a shell script (ksh, bash, sh) does, it is comfortable, if you have information about what other programs/scripts it calls.
How could one automate this task? Do you know any program or framework that can parse a shell script? This way for instance, I could recognize external command calls -- a step to the right direction.
For bash/sh/ksh, I think you can easily modify their source to log what has been executed. That would be a solution.
How about:
Get a list of distinct words in that script
Search $PATH to find a hit for each
?
bash -v script.sh ?
Bash's xtrace is your friend.
You can invoke it with:
set -x at the top of your script,
by calling your script with bash -x (or even bash --debugger -x),
or recursively by doing (set -x; export SHELLOPTS; your-script; )
If you can't actually run the script, try loading it into a text editor that supports syntax highlighting for Bash. It will color-code all of the text and should help indicate what is a reserved word, variable, external command, etc.

Resources