Reading user's PS1 from Swift command-line tool - swift

Is it possible to extract the user's PS1 from the environment in a Swift script, so that I can replicate their prompt?
I left a note for myself a few years ago saying that it "disappears from the environment in the context of the script", but I figured it would be useful to ask.
(I'm aware that this question won't necessarily work between shells, but assume that I only care about bash. Furthermore, I know I can't necessarily interpret everything in a user's prompt, but I would like to get it).

Try this in Swift script :
bash -i -c 'echo "$PS1"'

Related

Using PowerShell as VIM shell

I'm using the console version of VIM (not gvim) in Windows, and I have a question about using PowerShell as the shell.
I have set my shell to be powershell and I can run commands, but there's one thing I don't know. I have a bunch of things going on in my PowerShell profile, and I was wondering if it's possible to somehow pass something to PowerShell using VIM, so that in the profile I can check and decide what to do.
I know there's an option -NoProfile we can pass to powershell.exe, but my problem is that I don't want to ignore my whole profile, because I need some parts, such as aliases etc.
Thanks,

How do I get Perl to run an alias I've defined in BASH?

I have a script that opens up different files at the same time.
My problem here is that when I run system() on the alias I've defined in bash which points to /home/user1/Software/nc, perl tells me that it can't execute the alias because there is no file/directory at the current location.
I know that the alias works because when I invoke it directly in a shell, it opens fine.
Funny enough, I can do system("firefox") within my script fine, but not the alias. How do I use this alias in this script without it breaking?
Perl won't run bash, it will execute the command directly. You can call
bash -c your_command
instead of calling the command itself in Perl.
As it is, this doesn't load your aliases. You need to open an interactive shell, as in #MortezaLSC's answer. There supposedly is a way of loading aliases correctly in a non-interactive shell, but I can't figure it out.
But why don't you just use the command you have aliased to directly in perl? The only reason I could see not to do this, is if your alias is going to change in the future, but you will still want to run whatever command it points to. This seems weird and dangerous to say the least.
Aliases are designed to reduce the typing you do if you invoke commands with the same options etc all the time. They're not all-purpose macros for bash. Bash has functions for doing more complicated stuff, but why would you want to call non-trivial bash code from a perl script? It doesn't seem like you really need this here. Keep the complexity, and the potential for modification and failure, in one place (the perl script).
See a couple of answers to similar questions:
https://unix.stackexchange.com/a/1499/41977
https://superuser.com/a/183980/187150
If you're smart, you made it so your alias is only defined for interactive shells, so you'll have to launch bash and specify that you want an interactive shell using -i.
system('bash', '-i', '-c', 'shell command');
Is it working?
system 'bash -i -c "your alias parameter"';

Pipe works in Powershell but not CMD?

So the larger context of this problem is that it isn't possible, for whatever reason, to decrypt this file using, say, Bouncy Castle, so we're trying to do an automated command line with the normal gpg utility instead... I originally thought that would be quicker than trying to figure out why Bouncy Castle doesn't believe this is a real PGP-encrypted file, but I might have been wrong.
Here's the pipeline:
echo password | gpg --batch --yes --passphrase-fd 0 "filename"
This works perfectly in Powershell. Actually, several variations on this work perfectly in Powershell, but that's not the point...
The point is that I'm trying to run this in cmd.exe and it doesn't work there. Instead, I get an error saying that there has been no password provided and that, therefore, there is no secret key available and that, therefore, the file cannot be decrypted.
Given that the instructions I read for this are specifically for cmd.exe (not Powershell), I'm more than a little confused. Any idea what's going on here?
Apparently, the problem is that the password being passed through the pipeline includes a space--the one that appears between our hypothetical "d" and the pipe symbol itself. :)
So, for future reference, this works:
echo password|gpg --batch --yes --passphrase-fd 0 "filename"
Which, by the way, is exactly what the guide had said, but which I never caught onto because I did my initial testing in Powershell and didn't realize how picky cmd's echo command could be.

Perl - Cannot get command line arguments in without explicitly putting "perl" before script call [duplicate]

This question already has answers here:
#ARGV is empty using ActivePerl in Windows 7
(4 answers)
Closed 9 months ago.
I'm running ActivePerl 5.8.8 build 822 on Win7 x64. We're working on a project that is about 60% C++, 15% perl, etc. The Perl is heavily used to link bits and pieces and various small utility applications together to create and pack our final data. So, for example, our VS2005 solution has post build events to create hard links to DLL's using a post build perl script which lives at some location on our development drive (it is part of PATH env var).
I found out quickly, that without explicitly putting "perl" to call the interpreter in-front of the postbuild.pl script call, it wouldn't accept command line arguments. I tested this further simply by going to the cmd window and doing the same with a "hello world" style perl script. No command line arguments were passed in when I say "bleh.pl arg1 arg2". But when I say "perl bleh.pl arg1 arg2" I get command line arguments.
When this failure occurs, perl reads zero command line arguments, and the #ARGV variable empty or null (whatever this crazy language does). So they're simply not passed in.
This is an issue because there are hundreds if not thousands of calls to perl scripts which I fear are not behaving correctly, and it is unreasonable to think I should have to prefix every .pl script invocation with perl explicitly, not to mention we're using version control and I don't want to commit all these garbage changes nor manage them in my stash.
PERL env var exists and points at the folder where the perl binary lives. As well as PATHEXT has .PL in it for perl scripts. Likewise, my PATH contains the folder entries to get to the scripts and to perl also.
Any help on how to figure this out would be immensely appreciated! Also, when I installed ActivePerl (I've done so many times now trying to figure this out). I allowed it to change my Path and associate file extensions in windows, which you would think would be the solution.
Thank you!
Your association is broken (incomplete). First, open a console and execute
assoc .pl
You'll get something like
.pl=SOMETHING
Then, execute
ftype SOMETHING
You should get something like
SOMETHING="C:\SOMEWHERE\bin\perl.exe" "%1" %*
but you'll get something like the following instead:
SOMETHING="C:\SOMEWHERE\bin\perl.exe" "%1"
To fix it, execute
ftype SOMETHING="C:\SOMEWHERE\bin\perl.exe" "%1" %*

How can I find out what script, program, or shell executed my Perl script?

How would I determine what script, program, or shell executed my Perl script?
Example: I might want to have human readable output if executed from shell (customized for each type of shell), a different type of output if called as a script from another perl script, and a machine readable format if executed from a program such as a continuous integration server.
Motivation: I have a tool that changes its output based on which shell executes it. I'd normally implement this behavior as an option to the script, but this tool's design doesn't allow for options. Other shells have environment variables that indicate what shell is running. I'm working on a patch to support Powershell, which has no such special variable.
Edit: Many of these answers happen to be linux specific. Unfortuantely, Powershell is for Windows. getppid, the $ENV{SHELL} variable, and shelling out to ps won't help in this case. This script needs to run cross-platform.
You use getppid(). Take this snippet in child.pl:
my $ppid = getppid();
system("ps --no-headers $ppid");
If you run it from the command line, system will show bash or similar (among other things). Execute it with system("perl child.pl"); in another script, e.g. parent.pl, and you will see that perl parent.pl executed it.
To capture just the name of the process with arguments (thanks to ikegami for the correct ps syntax):
my $ppid = getppid();
my $ps = `ps --no-headers -o cmd $ppid`;
chomp $ps;
EDIT: An alternative to this approach, might be to create soft links to your script, make the different contexts use different links to access your script and inspect $0 to build logic around that.
I would suggest a different approach to accomplish your goal. Instead of guessing at the context, make it more explicit. Each use case is wholly separate, so have three different interfaces.
A function which can be called inside a Perl program. This would likely return a Perl data structure. This is far easier, faster and more reliable than parsing script output. It would also serve as the basis for the scripts.
A script which outputs for the current shell. It can look at $ENV{SHELL} to discover what shell is running. For bonus points, provide a switch to explicitly override.
A script which can be called inside a non-Perl program, such as your continuous integration server, and issue machine readable output. XML and/or JSON or whatever.
2 and 3 would be just thin wrappers to format the data coming out of 1.
Each is tailored to fit its specific need. Each will work without heuristics. Each will be far simpler than trying to guess the context and what the user wants.
If you can't separate 2 and 3, have the continuous integration server set an environment variable and look for it.
Depending on your environment, you may be able to pick it up from the environment variables. Consider the following code:
/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh
On my Ubuntu system, it gets me:
'SHELL' => '/bin/bash',
So I guess that says I'm running perl from a bash shell. If you use something else, the SHELL variable may give you a hint.
But let's say you know you're in bash, but perl is run from a subshell. Then try:
/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh
You will find:
'_' => '/bin/sh',
'SHELL' => '/bin/bash',
So the shell is still bash, but bash has a variable $_ which also show the absolute filename of the shell or script being executed, which may also give a valuable hint. Similarily, for other environments there will most probably be clues left in the perl %ENV hash that should give you valuable hints.
If you're running PowerShell 2.0 or above (most likely), you can infer the shell as a parent process by examining the environment variable %psmodulepath%. By default, it points to the system modules under %windir%\system32\windowspowershell\v1.0\modules; this is what you would see if you examine the variable from cmd.exe.
However, when PowerShell starts up, it prepends the user's default module search path to this environment variable which looks like: %userprofile%\documents\windowspowershell\modules. This is inherited by child processes. So, your logic would be to test if %psmodulepath% starts with %userprofile% to detect powershell 2.0 or higher. This won't work in PowerShell 1.0 because it does not support modules.
This is on Windows XP with PowerShell v2.0, so take it with a grain of salt.
In a cmd.exe shell, I get:
PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\
whereas in the PowerShell console window, I get:
PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP
owerShell\v1.0\Modules\
where E:\Home\user is where my "My Documents" folder is. So, one heuristic may be to check if PSModulePath contains a user dependent path.
In addition, in a console window, I get:
!::=::\
in the environment. From the PowerShell ISE, I get:
!::=::\
!C:=C:\Documents and Settings\user