Thread overview
2.068.0 std.process.executeShell how to set the shell?
Sep 01, 2015
albatroz
Sep 02, 2015
Jonathan M Davis
Sep 02, 2015
Jonathan M Davis
Sep 02, 2015
albatroz
Sep 03, 2015
Jonathan M Davis
Sep 03, 2015
albatroz
September 01, 2015
Hi, since the upgrade to the latest version the function executeShell (also the other functions), is not working has it used to be, older versions of the compiler did not require any change or setting the SHELL.

How to change the SHELL, that is used by executeShell? userShell will always return /bin/sh.

I've tested by setting the SHELL to /bin/bash using the environment function. If I execute echo $SHELL inside the executeShell it will show /bin/bash has expected.

My issue is that the command I'm executing inside executeShell is throwing and error and showing that the execution is done by /bin/sh.

My code:
executeShell("diff -u <(echo "~data1~") <(echo "~data2~")");

Output:
/bin/sh: 1: Syntax error: "(" unexpected

This is caused by a limitation from /bin/sh that cannot perform process substitution.

Can this commit be the reason? https://github.com/D-Programming-Language/phobos/commit/a524a3571b18e440c4dd751fcf4e2d00b834fb22
September 02, 2015
On Tuesday, September 01, 2015 21:55:28 albatroz via Digitalmars-d-learn wrote:
> Hi, since the upgrade to the latest version the function executeShell (also the other functions), is not working has it used to be, older versions of the compiler did not require any change or setting the SHELL.
>
> How to change the SHELL, that is used by executeShell? userShell will always return /bin/sh.
>
> I've tested by setting the SHELL to /bin/bash using the environment function. If I execute echo $SHELL inside the executeShell it will show /bin/bash has expected.
>
> My issue is that the command I'm executing inside executeShell is throwing and error and showing that the execution is done by /bin/sh.
>
> My code:
> executeShell("diff -u <(echo "~data1~") <(echo "~data2~")");
>
> Output:
> /bin/sh: 1: Syntax error: "(" unexpected
>
> This is caused by a limitation from /bin/sh that cannot perform process substitution.
>
> Can this commit be the reason? https://github.com/D-Programming-Language/phobos/commit/a524a3571b18e440c4dd751fcf4e2d00b834fb22

Well, based on the information in the corresponding bug report and comments in the PR, it sounds like it's generally considered best practice to always use /bin/sh, because it's consistent, whereas who knows what SHELL is set to. Sure, it's common on Linux systems for it to be bash, but there are plenty of Linux systems where it isn't, and other POSIX systems like FreeBSD typically have sh as the default, and many users commonly use shells like csh or tcsh rather than bash. And of course, the folks who want a particularly fancy shell use zsh. So, while bash is probably the most commonly used shell, it's still fairly common for folks to use other shells, and if you want consistent behavior, you need sh.

That being said, userShell clearly now is inconsistent with its documentation, and it probably would have been better to just make the other std.process functions use /bin/sh than to change userShell, since SHELL really is the user's shell.

Now, if you want to specifically force the use of bash, I think that you're going to have to use execute or spawnProcess and use /bin/bash as the command. That's definitely more annoying, but if you look at the implementation for spawnShell, it sets arguments to pass to spawnProcess to spawn the shell. executeShell and execute seem more complicated to figure out how they work, but presumably it's possible to pass a similar command to execute in order to simulate executeShell with /bin/bash.

- Jonathan M Davis

September 02, 2015
On Wednesday, 2 September 2015 at 01:26:23 UTC, Jonathan M Davis wrote:
[snip]

https://issues.dlang.org/show_bug.cgi?id=15000

- Jonathan M Davis
September 02, 2015
On Wednesday, 2 September 2015 at 01:46:18 UTC, Jonathan M Davis wrote:
> On Wednesday, 2 September 2015 at 01:26:23 UTC, Jonathan M Davis wrote:
> [snip]
>
> https://issues.dlang.org/show_bug.cgi?id=15000
>
> - Jonathan M Davis

Thank you for your reply and for the bug report.

Looking at your suggestions I do not fully understand/agree.

executeShell has been one of the easiest ways for us to interact with the shell, all other functions require more work to implement. Being able to define the shell to be used is something that makes sense across all functions in std.process.

Honestly being able to set a different variable name instead of SHELL would make more sense. It would not take the default shell from the user thus using /bin/sh and would allow us to change it if desired with a different value. The change would be minimal across code and documentation.

But that's just my suggestion, I'm not a library developer. I understand that all variants may have their own issues, but taking away from the developer the power to make decisions also doesn't seem a good option.

Anyway I would like to ask if you can help to understand why this simple example using execute fails?

  auto outputDiff = execute ( ["bash","echo"] );
  writeln (outputDiff.output);

Output:
/bin/echo: /bin/echo: cannot execute binary file

At the moment some of the uses I had are not working and I'm not able to implement any workaround.

Obrigado
September 03, 2015
On Wednesday, September 02, 2015 15:28:35 albatroz via Digitalmars-d-learn wrote:
> On Wednesday, 2 September 2015 at 01:46:18 UTC, Jonathan M Davis wrote:
> > On Wednesday, 2 September 2015 at 01:26:23 UTC, Jonathan M
> > Davis wrote:
> > [snip]
> >
> > https://issues.dlang.org/show_bug.cgi?id=15000
> >
> > - Jonathan M Davis
>
> Thank you for your reply and for the bug report.
>
> Looking at your suggestions I do not fully understand/agree.
>
> executeShell has been one of the easiest ways for us to interact with the shell, all other functions require more work to implement. Being able to define the shell to be used is something that makes sense across all functions in std.process.
>
> Honestly being able to set a different variable name instead of SHELL would make more sense. It would not take the default shell from the user thus using /bin/sh and would allow us to change it if desired with a different value. The change would be minimal across code and documentation.
>
> But that's just my suggestion, I'm not a library developer. I understand that all variants may have their own issues, but taking away from the developer the power to make decisions also doesn't seem a good option.

Oh, it would be nice to be able to specify the shell (and feel free to add a comment on that to the bug report). It's just that spawnShell and executeShell already have a lot of parameters, and it would kind of ugly to add another. Not to mention, it would probably have to go on the end after several parameters with default arguments, forcing you to list all of the default arguments explicitly just so that you can list the shell. So, while in principle, listing the shell, would be nice. In practice, I'm not sure how to add it cleanly to the current API, and it _is_ possible to use execute or spawnProcess to run a specific shell.

> Anyway I would like to ask if you can help to understand why this simple example using execute fails?
>
>    auto outputDiff = execute ( ["bash","echo"] );
>    writeln (outputDiff.output);
>
> Output:
> /bin/echo: /bin/echo: cannot execute binary file
>
> At the moment some of the uses I had are not working and I'm not able to implement any workaround.

That's because you're doing the equivalent of

bash echo

on the command line, and if you try that, you'll notice that you get the same error there. What you need to do instead, per the bash man page, is to run bash with the -c flag, where -c takes the command you want to run. So, you can do something like

auto result = execute(["bash", "-c", "echo world"]);

though what gets printed doesn't seem to appear on the command line any more than if you echoed with executeShell. If you want that, you'd have to use spawnShell or spawnProcess, e.g.

auto result = wait(spawnProcess(["bash", "-c", "echo world"]));

But if you don't care about the commands appearing on the command line, then execute works just fine. In either case, the key thing that you're missing is -c.

- Jonathan M Davis

September 03, 2015
On Thursday, 3 September 2015 at 05:07:10 UTC, Jonathan M Davis wrote:
> key thing that you're missing is -c.
>
> - Jonathan M Davis

Hi Jonathan, I would just like to say thank you for the time you took to help and clarify.

Obrigado