www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - 2.068.0 std.process.executeShell how to set the shell?

reply "albatroz" <rmcjustino gmail.com> writes:
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
Sep 01 2015
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
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
Sep 01 2015
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Sep 01 2015
parent reply "albatroz" <rmcjustino gmail.com> writes:
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
Sep 02 2015
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
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
Sep 02 2015
parent "albatroz" <rmcjustino gmail.com> writes:
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
Sep 03 2015