Sending a pipe as an argument to an external program in Powershell? - powershell

I keep getting the following error when running a command to look for the most recently modified directory in my path: remotely from PowerShell:
head: The term 'head' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line 1: char: 95
+ ... d /somedir ; (lastmod=$(ls -tda -- */ | head -n 1); ....
I'm running code something along the lines of the following:
& plink "bob#server" "cd /somedir ; (lastmod=$(ls -tda -- */ | head -n 1); ls -la $lastmod)"

You've encapsulated your commands in double-quotes so the $ signs are being expanded by PowerShell. If you use single quotes this won't happen.

Just to add on to Bruce's answer, you could also escape the special character from your double-quoted string using the grave accent (`), which is the escape character in powershell.
& plink "bob#server" "cd /somedir ; (lastmod=$(ls -tda -- */ `| head -n 1); ls -la $lastmod)"
This means that if you did need any variables inside of your string, you could still utilize special characters.

Related

Execute a bat file with a variable name in the path

I am having a problem executing a powershell script where I want to point to different versions of a bat file based on some arguments
Hard coding the path as follows works with no issues:
& 'C:\Program Files\MATLAB\R2022a\bin\mcc.bat' -W $command -T link:exe ...
but replacing a folder name with a variable causes it to fail:
$Matlab_version = "R2022a"
& 'C:\Program Files\MATLAB\$Matlab_version\bin\mcc.bat' -W $command -T link:exe
with the following output:
& : The term 'C:\Program Files\MATLAB\%$Matlab_version%\bin\mcc.bat' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:3
+ & 'C:\Program Files\MATLAB\%$Matlab_version%\bin\mcc.bat' -W $comman ...
I've tried even creating a variable with the path name
$mcc_loc = & 'C:\Program Files\MATLAB\$Matlab_version\bin\mcc.bat'
Write-Host $mcc_loc
which produces a string with the correct path. Any help is greatly appreciated. My dumb solution is to have an if statement for each $Matlab_version and hard code it in there but I'm sure there has to be a more elegant solution
It's because you are using single quotation marks.
variables will not be interpreted within single marks, everything will be taken as a literal string.
use double quotes instead when passing in variables mid string.
example:
You need to change the single quote ' to double quote "
Double-quoted strings
A string enclosed in double quotation marks is an expandable string. Variable names preceded by a dollar sign ($) are replaced with the variable's value before the string is passed to the command for processing.
$Matlab_version = "R2022a"
& "C:\Program Files\MATLAB\$Matlab_version\bin\mcc.bat" -W $command -T link:exe
See about_Quoting_Rules

kdb string path miss quotation mark

I would like to join strings for file name and shell script so I can run the command line in kdb for ftp transfer.
But there are quotations in quotation marks. not sure how to add / in there.
This is the code I have:
host:"abc.com";
usr:"def";
path:"get /home/eddie/abc.csv /home/terry/";
cmd:" " sv ("/home/kdb/eddie/ftp.sh";host;usr;path);
system cmd;
So the path will not have quotation mark and will be running error. How can I solve this problem?
You can escape quotes with \ e.g. "\"Matt\"" but I don't think that's your issue. It looks like you are attempting to use get in the system command. This is a kdb keyword and your OS will not recognise it. You should just be passing the location of the csv to your ftp script.
Edit:
You may also need sh in the system command.
cat test.sh
echo $1
system "test.sh hello"
sh: ./test.sh: Permission denied
'os
system "sh test.sh hello"
"hello"
Assuming that you simply want quotes within a string, it may just be as simple as using .Q.s1 aka -3!, see https://code.kx.com/q/ref/dotq/#qs1-string-representation
q)" " sv ("/home/kdb/eddie/ftp.sh";host;usr;.Q.s1 path)
"/home/kdb/eddie/ftp.sh abc.com def \"get /home/eddie/abc.csv /home/terry/\""
q)" " sv ("/home/kdb/eddie/ftp.sh";host;usr;-3!path)
"/home/kdb/eddie/ftp.sh abc.com def \"get /home/eddie/abc.csv /home/terry/\""

PowerShell command only works without spaces between arguments

I try certain source codes using PowerShell to extract an password protected archive using 7zip:
This command doesn' work (7zip is an alias for $7zipPath):
& 7zip x "$zipFile" -o "$output" -p $zipFilePassword
I get the this error:
Command Line Error:
Too short switch:
But when I remove the spaces between the variables -o and -p, the archive can be extracted. This behaviour confuses me with other command line tools like git etc.? Why is it so?
The behavior is specific to 7-Zip (7z.exe) and applies to whatever program (shell) you invoke it from:
Deviating from widely used conventions observed by CLIs such as git, 7z requires that even switches (options) that have mandatory arguments, such as -o and -p, have the argument directly attached to the switch name - no spaces are allowed:
& 7zip x $zipFile -o"$output" -p"$zipFilePassword"
Note that you normally need not enclose variable references in PowerShell in "..." (note how $zipFile isn't), even if they contain spaces. However, in order to attach them directly to switch names, you do.
Alternatively, you could enclose the entire token - switch name and argument - in double quotes:
& 7zip x $zipFile "-o$output" "-p$zipFilePassword"

How can I ensure my autocompleted spaces are fed into my function properly?

I'm using zsh, and am trying to write a function to operate on a URL and a pathname:
function my-function
{
somecommand --url $1 $(readlink -f $2)
}
(to complicate things somewhat, the function actually uses sh syntax, as it is sourced from my ~/.zshrc using a trick like this). The readlink is there to expand symlinks and ensure directories such as . are evaluated correctly (the directory name is stored for later use by somecommand).
When I type a command from the command-line like this:
my-function http://example.org/example /tmp/myexampledirectory
... it works fine, even if I autocomplete the directory name. However, if the directory name contains spaces, zsh completes it like this:
my-function http://example.org/example /tmp/My\ Example\ Directory
For most "normal" commands (cp, mv, etc.) that never seems to cause a problem. However, in my case, somecommand sees $2 as only being /tmp/My - presumably the rest is seen as another argument.
How can I avoid this situation? I would prefer not to alter the standard zsh autocompletion, but rather find a way for my function to handle this.
The zsh completion system works very well here, and the solution is very simple, just put double-quotes around the readlink argument in the script:
somecommand --url $1 $(readlink -f "$2")
The point is that without quotes readlink removes backslashes which escape whitespaces. Compare three results:
1. Without backslashes and quotes readlink -f assumes that there are three different files/directories (with default path in current directory) and produces
$ readlink -f /tmp/My Example Directory
/tmp/My
/home/jimmij/Example
/home/jimmij/Directory
2. With escaping backslashes but without quotes readlink -f understands that there is only one directory, but removes backslashes from output, so that somecommand takes three separate arguments
$ readlink -f /tmp/My\ Example\ Directory
/tmp/My Example Directory
3. With backslashes and with double-quotes readlink -f gives the output with backslashes what is (most probably) expected by somecommand
$ readlink -f "/tmp/My\ Example\ Directory"
/tmp/My\ Example\ Directory
BTW, as a rule of thumb: if there are any problems with whitespaces in the shell-like scripts (bash, zsh, whatever) the first thing to play with is different quotation marks around variables.

Execute command with arguments and a pipe

I'm trying to execute the command below in a PowerShell script
C:\PATH TO GPG\gpg.exe --output OUTPUTFILE.csv --batch --passphrase-fd 0 --decrypt C:\PATH TO INPUT\INPUTFILE.txt < C:\PATH TO PASS\Passphrase.txt
When I assign various sections of the command to variables and then combine them in a command varible and try and execute it as follows:
$decryptCommand = "${gpg} --output ${dateStamp}.csv --batch --passphrase-fd 0 --decrypt ${fileName} < ${passphraseFile}"
&$decryptCommand
I receive the following error:
The term 'XXXX' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
I have tried to surround various parts of the command in single and double quotes but nothing I've tried seems to work.
Is there something extra I should be doing to execute this command from a PowerShell script?
There are several problems with you script. First, you don't need to surround variable with {}, secon - you have to pass parameters seperately, like this:
&$gpg --output $dateStamp.csv --batch --passphrase-fd 0 --decrypt $fileName < $passphraseFile
The only thing I'm not sure about is < symbol. It might be the case that you will need to escape it with '