Redirecting command output:
For example:
echo "Foo `./print_5_As.rb`"
would echo "Foo AAAAA"
The PowerShell syntax is based on the POSIX ksh syntax
(and interestingly not on any of Microsoft's languages
like CMD.EXE, VBScript or Visual Basic for Applications),
so many things work pretty much the same as in Bash. In
your case, command substitution is done with
echo "Foo $(./print_5_As.rb)"
in both PowerShell and Bash.
Bash still supports the ancient way (backticks), but
PowerShell cleaned up the syntax and removed redundant
constructs such as the two different command substitution
syntaxes. This frees up the backtick for a different
use in PowerShell: in POSIX ksh, the backslash is used as
escape character, but that would be very painful in
PowerShell because the backslash is the traditional path
component separator in Windows. So, PowerShell uses the
(now unused) backtick for escaping.
In PowerShell, you use $( ) to evaluate subexpressions...
For example:
PS C:\> "Foo $(./print_5_As.rb)"
Foo AAAAA
In CMD.EXE there is no direct equivalent. But you can use the FOR command to achieve what you want.
Do something like the following:
FOR /F "usebackq" %x IN (`./print_5_As.rb`) DO #echo Foo %x
or
FOR /F %x IN ('"./print_5_As.rb"') DO #echo Foo %x
You might need to set delimiter to something else than the default, depending on how the output looks and how you want to use it. More details available in the FOR documentation at https://technet.microsoft.com/en-us/library/bb490909.aspx
Related
I have multiple doskeys defined in following fashion:
doskey ll=dir $*
doskey grep=findstr $*
doskey make=mingw32-make $*
I want to use them in conjunction in one-line commands such as:
ll | grep my_folder
or
make && make install
But after first pipe/not/and operator, the doskeys no longer appear to exist since the cmd won't recognize the commands. For example, while single make command works, calling echo hello && make will tell me the make is not recognized as a command.
Is there a way to preserve the doskey context so I can chain them together as written above?
Also, the same issue applies to running batch files using the doskeys, is there a way to preserve the context for that too?
I've heard about the $T argument of doskey, but I am not quite sure if I understand it.
Thanks for help in advance
I had a similar issue...
Following macro was not handling the section after the | character:
doskey system=systeminfo | findstr /C:"OS"
But, the following did:
doskey system=systeminfo $B findstr /C:"OS"
So, looks like doskey's pipe symbol is $B.
I'm in the unfortunate position to be forced to invoke a program via echo <input> | program.exe. Of course, I wondered how to escape <input> and found:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Escape angle brackets in a Windows command prompt
In essence, it seems sufficient to escape all special chars with ^. Out of curiosity I still would like to know, why echo ingores double-quote escaping in the first place:
C:\>echo "foo"
"foo"
C:\>
Is there any normative reference?
Bonus question: How to echo the strings on and off with the echo command?
Edit: I just found this. I states that only |<> need to be escaped. However, expansion like %FOO% still work.
Special characters like ^, &, (, ), <, >, %, ! and " may cause problems with echo, also when trying to echo a string into a pipe; odd numbers of " are particularly difficult to handle.
Building escape sequences can be very complicated particularly with pipes, because such initiates new cmd instances for either side, so multi-escaping might become necessary.
The only reliable way to pipe the output of echo into a program is to use a variable holding the string to return and to apply delayed expansion, but within the left side of the pipe, like this:
cmd /V /C echo(^^!VARIABLE^^!| program.exe
Note the double-escaping of ! like ^^!, which makes this code even work when delayed expansion is also enabled in the parent cmd instance. There must not be a SPACE in front of the |, because this was echoed too otherwise. Note that echo terminates the output by a line-break.
Here's a simple .bat file that shows the first three arguments with which the bat file is executed:
#echo 1: %1
#echo 2: %2
#echo 3: %3
When I execute the bat file like so
c:\> x:\show_parameters.bat "foo bar" baz "one two three"
the output is
1: "foo bar"
2: baz
3: "one two three"
I was surprised, because I didn't expect the double quotes to be passed as part of the arguments.
When I use a Perl script to show the values of the parameters
my $arg_cnt = 1;
for my $arg (#ARGV) {
printf "%2d: %s\n", $arg_cnt, $arg;
$arg_cnt++;
}
and execute the script like so
c:\> x:\show_parameter.pl "foo bar" baz "one two three"
it prints
1: foo bar
2: baz
3: one two three
that is, without any double quotes. This is the, imho, expected behaviour for the bat variant.
So, Why are the arguments passed differently to the bat file?
TL;DR: It depends on the shell implementation. On windows, the cmd console quoting uses different rules from the bash shell. source
I believe you're looking for:
#echo 1: %~1
#echo 2: %~2
#echo 3: %~3
See the documentation.
The Tilde character has special "modifier" meaning with batch parameters. If you think about it, Perl and batch are two different languages, and when a program is sent parameters, think of it like it's passed a query string, except it's upto the language to decide how to parse it. Really what you pass to the program is one-long parameter but the program splits on spaces while keeping in mind quotes and escaping.
You can also see #echo 0: %0 will show you the program in quotes while #echo 0: %~0 removes the double quotes.
To see the full line of "arguments" passed to the script, without being parsed, you'd do:
#echo *: %*
As you can see, the script is really passed one long argument and has to be parsed first, keeping spaces and quotes, and escape characters such as ^ in mind, in order to create the concept of multiple "arguments".
In terms of Perl's behavior, my guess is that Perl does this automagically for you when populating ARGV. Could check its source code if you're interested in the logic Perl is using.
Edit:
After playing with it for a while, I'm starting to think this is beyond Perl's control. I'm noticing the same behavior with PHP as well when testing print_r($argv); from commandline and it also loses its quotes.
You can see Perl is getting sent the parameters with quotes by running:
use Win32::API;
my $GetCommandLine = Win32::API->new('kernel32',
'GetCommandLine', [ ] , 'P' );
$cmdline = $GetCommandLine->Call();
print $cmdline;
But then you'd need to parse that if you wanted just the parameters and not the full command line command.
There's a question posted here exactly like yours:
http://www.nntp.perl.org/group/perl.beginners/2002/07/msg29597.html
To paraphrasing Peter Scott's answer there on the 2nd page: the shell does the whitespace splitting and dequoting before the program sees the arguments and it makes no difference what language the program is written in. So you'll have to find a workaround.
The answer is pretty consistent that it's a shell issue the more I research it.
For example even in Python, it's the same issue.
So why does batch give different results? It depends on the shell implementation. On windows, the cmd console quoting uses different rules from the bash shell.
consider
call :somesubroutine %*
Without the quotes, somesubroutine would see 6 arguments. With its sees 3.
Really a matter of definition, but batch seems to tell the truth here.
Consider also what happens with
x:\show_parameters.bat "foo bar" "" "one two three"
When I run a command like this:
someprogram.exe --param="Value!"
the Windows shell will treat the exclamation mark in my value as a special character. Is there a way to suppress that or is escaping the only way around this? (Exclamation mark is escaped by ^^! if I'm not mistaken.)
EDIT: Weird thing that cmd.exe does not do the expansion but cmder does. I thought they are just two different GUIs to the same underlying shell? Maybe there's a switch for the expansion behavior? I tried SETLOCAL DisableDelayedExpansion but with no effect.
Redirecting command output:
For example:
echo "Foo `./print_5_As.rb`"
would echo "Foo AAAAA"
The PowerShell syntax is based on the POSIX ksh syntax
(and interestingly not on any of Microsoft's languages
like CMD.EXE, VBScript or Visual Basic for Applications),
so many things work pretty much the same as in Bash. In
your case, command substitution is done with
echo "Foo $(./print_5_As.rb)"
in both PowerShell and Bash.
Bash still supports the ancient way (backticks), but
PowerShell cleaned up the syntax and removed redundant
constructs such as the two different command substitution
syntaxes. This frees up the backtick for a different
use in PowerShell: in POSIX ksh, the backslash is used as
escape character, but that would be very painful in
PowerShell because the backslash is the traditional path
component separator in Windows. So, PowerShell uses the
(now unused) backtick for escaping.
In PowerShell, you use $( ) to evaluate subexpressions...
For example:
PS C:\> "Foo $(./print_5_As.rb)"
Foo AAAAA
In CMD.EXE there is no direct equivalent. But you can use the FOR command to achieve what you want.
Do something like the following:
FOR /F "usebackq" %x IN (`./print_5_As.rb`) DO #echo Foo %x
or
FOR /F %x IN ('"./print_5_As.rb"') DO #echo Foo %x
You might need to set delimiter to something else than the default, depending on how the output looks and how you want to use it. More details available in the FOR documentation at https://technet.microsoft.com/en-us/library/bb490909.aspx