On macOS run
osascript -e 'display notification "FOO" with title "TITLE"'
Show notification, just like in bash
PS /> osascript -e 'display notification "FOO" with title "TITLE"'
21:24: execution error: The variable FOO is not defined. (-2753)
PS /> bash
bash-3.2$ osascript -e 'display notification "FOO" with title "TITLE"'
bash-3.2$
> $PSVersionTable
Name Value
---- -----
PSVersion 6.0.0-alpha
PSEdition Core
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 3.0.0.0
GitCommitId v6.0.0-alpha.14
CLRVersion
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
The following change does work.
osascript -e 'display notification \"FOO\" with title \"TITLE\"'
Per the man page.
-e statement
Enter one line of a script. If -e is given, osascript will not look for a filename in the argument list.
Multiple -e options may be given to build up a multi-line script. Because most scripts use characters that
are special to many shell programs (for example, AppleScript uses single and double quote marks, ``('',
``)'', and ``*''), the statement will have to be correctly quoted and escaped to get it past the shell
intact.
@thezim good to know, thank you!
I still think there is an issue, because it's super unintitive for me, why I need to escape these quotes, when the whole parameter is already wrapped in the single-quoted string.
Also it related to the pillar of "making PS more compatible with existing shells to allow more commands work thru copy-paste".
@vor I agree. I would prefer your example to work too.
Invoke-AppleScript would be a nice cmdlet for macOS. Following would lead me to believe is could be done.
http://jonathanpeppers.com/Blog/xamarin-ios-under-the-hood-calling-objective-c-from-csharp
https://docs.microsoft.com/en-us/dotnet/articles/standard/native-interop
@vors This works too.
'display notification "FOO" with title "TITLE"' | osascript
Repro (using test code in our repo):
PS> cd test/tools/EchoArgs
PS> dotnet run 'a "b" c'
Arg 0 is <a b c>
PS> bash
$ dotnet run 'a "b" c'
Arg 0 is <a "b" c>
Note that the behavior is consistent with Windows, but maybe it shouldn't be.
Why is it this way on Windows? If I recall correctly, this behavior was a major annoyance.
Correct me if I'm wrong, but isn't this a duplicate of https://github.com/PowerShell/PowerShell/issues/1995 ?
@lzybkr I think it absolutely must be consistent with Windows, but double escaping should not be necessary on any platform.
@vors Note that in the workaround on macOS, the double quotes are being escaped with '\'. PowerShell doesn't treat \ as the escape character so clearly osascript is doing it's own escape processing.
@lzybkr the value of argv[0] is exactly what I'd expect it to be. Since windows CreateProcess passes arguments as a simple string, process startup code needs to break that string up into individual arguments. It does this by processing the quotes that are passed, doing quote removal for string arguments.
@BrucePay - The annoyance is that calling a process differs from calling a command:
#437 PS> function myechoargs { for($i = 0; $i -lt $args.Length; $i++) { "arg ${i}: <$($args[$i])>"}}
#438 PS> myechoargs 'a "b" c'
arg 0: <a "b" c>
#439 PS> echoargs.exe 'a "b" c'
arg 0: <a b c>
Add to this - the behavior of bash differs from windows - it is more like calling a script/function than an executable.
I don't see a perfect solution. As I see it, the incompatible goals are:
People do find the behavior on Windows confusing.
People do find many command lines for cmd/bash and should just work in PowerShell - this is one example where it doesn't.
PowerShell Core could chose to break compatibility with Windows PowerShell to deliver on goals 1, 2, and 3.
We could make no changes, and we've delivered on 3 and 4.
@BrucePay Although Windows does only send a single Commandline to the new Process, almost every CLI-App splits this Commandline according to these rules. Therefore Powershell should build the Commandline in a way, that matches those rules instead of just sometimes adding quotes around arguments.
Almost every other modern Commandshell on windows does this:
linebuf::fromargv
)list2cmdline
)BuildCommandLine
, Comment: "N backslashes followed a quote -> insert N * 2 + 1 backslashes then a quote.")People also expect this from Powershell. See:
@lzybkr I think 4.
is not really a Problem, as it never really worked on Windows and even changed from time to time. For example in Powershell on Windows 10 (PSVersion: 5.1.14393.693; PSEdition: Desktop; BuildVersion: 10.0.14393.693) it's completely impossible to send a"b c
to the argv[1]
of the next Process via a normal call:
echoargs 'a\"b c'
-> Commandline: \path\to\echoargs.exe a\"b c
echoargs '"a\"b c"'
-> Commandline: \path\to\echoargs.exe ""a\"b c""
Necessary Commandline for argv[1]
=a"b c
: \path\to\echoargs.exe "a\"b c"
The only option to accomplish this is via --%
, but that gets really botched, if one needs to pass content from calculations or variables.
@TSlivede - I feel comfortable saying somebody depends on the current behavior.
That said, compatibility can't really be guaranteed (different runtimes amongst other big differences), so it's really a best effort.
Personally I'm in favor of the breaking change - far too many people avoid the easy way of running an external command because of issues like this.
@vors asked in https://github.com/PowerShell/PowerShell/issues/1995 if anybody wants to start an RFC process.
I wrote a draft, here it is.
Most helpful comment
@TSlivede - I feel comfortable saying somebody depends on the current behavior.
That said, compatibility can't really be guaranteed (different runtimes amongst other big differences), so it's really a best effort.
Personally I'm in favor of the breaking change - far too many people avoid the easy way of running an external command because of issues like this.