Working on a C++ Unix program executed on the command line (MacOs).
I call system("history -s SOMETHING") in it to add SOMETHING to the history of the user's shell, but I guess the call is opening a new sub-shell.
My question is : can I execute the system call on the "current" shell (the one used to run the program) ?
To be clear I want to find the SOMETHING in my shell history when I quit the program.
Thanks !
As far as I know, it's not possible in general.
If you're using bash, and since this is only for you:
Enable history appending in .bashrc:
shopt -s histappend
Launch a login bash shell in main:
system("bash -li -c 'history -s SOMETHING'");
and then refresh your history:
history -n
The history -n can be automated - you can execute it inside your prompt, for instance.
Figuring out how to do that left as an exercise.
(Disclaimer: I have only tried this in Ubuntu under the Windows Subsystem for Linux, but it should work very similarly on a Mac.)
It isn't possible. The usual work around -- not applicable if there is other wanted output -- is to make your program prints the wanted command and then execute it. For instance
#include <iostream>
int main() {
std::cout << "history -s SOMETHING\n";
return 0;
}
and then
eval $(/path/to/my/exe)
For ease of use, you can put that in a shell function
myfn() {
eval $(/path/to/my/exe)
}
that you can simply use
myfn
Related
TL;DR; I guess the shell that std::system use, is sh. But, I'm not sure.
I tried to print the shell, using this code: std::system("echo $SHELL"), and the output was /bin/bash. It was weird for me. So, I wanted to see, what happens if I do that in sh? And, the same output: /bin/bash. Also, if I use a command like SHELL="/usr/bin/something", to set the SHELL variable to another string, it will print the new string that I set to it (/usr/bin/something), and it looks it's not a good way to see what shell it's using. Then, I tried to check it, using the ps command, and the output was: bash, a.out, ps. It was weird to see bash in this list. So, I created a custom shell, and change the shell in gnome-terminal to it:
#include <iostream>
int main()
{
std::string input;
while (true)
{
std::string command;
std::getline(std::cin, command);
std::system(command.c_str());
}
}
Now, it's easier to test, and I think, the results is better.
Then, I tried to test the ps command again, but in the custom shell, and the results was: test_shell, ps.
It was weird again. How the shell isn't sh, nor bash? And, the final test I did was: echo $0. And, the results was sh, in both custom shell, and normal program.
Edit
It seems like /bin/sh is linked to /bin/bash (ll /bin/sh command's output is /bin/sh -> bash), and actually, it seems like the only difference between sh and bash is filename, and the files's contents are the same. I checked the difference between these files with diff command too:
$ xxd /bin/sh > sh
$ xxd /bin/bash > bash
$ diff sh bash
(+ Yes, $SHELL doesn't means the running shell (I didn't know that when I was testing, and I just wanted to see what happens))
The GNU sources (https://github.com/lattera/glibc/blob/master/sysdeps/posix/system.c) say
/bin/sh
So, whatever /bin/sh is hardlinked to is the shell invoked by std::system() on Linux.
(This is correct, as /bin/sh is expected to be linked to a sane shell capable of doing things with the system.)
According to cppreference.com, std::system
calls the host environment's command processor (e.g. /bin/sh, cmd.exe, command.com)
This means the shell used will depend on the operating system.
On any POSIX OS (including Linux), the shell used by std::system is /bin/sh. (Though as the OP points out, /bin/sh could be a symlink to another shell.)
As for the SHELL environment variable, as has been pointed out in the comments, this environment variable cannot be used to reliably identify the running shell program. SHELL is defined by POSIX to
represent a pathname of the user's preferred command language interpreter
(source)
I've run into a snag, I'm trying to implement a linux shell program of sorts with C++ and many of my commands seem to work, however, when I try to get the history(list all recently executed commands) I get an error of "sh: 1: history: not found" the below line is all that runs in the area, what is the issue?
system("history"); //produces the error above ^
If I do
$ history
from the command line it's fine...why is it not fine in C++?
system executes a program using /bin/sh, but history is a bash builtin.
You might look at the contents of ~/.bash_history instead. (Note (by leemes) .bash_history is only updated after closing a previous bash session, as well as it is not updated by executing a command with system.)
Because it's a bash shell builtin not necessarily accessible through /bin/sh -c` (which may be the bourne shell).
I recently decided to start teaching myself C++ and thought a simple encryption project would be a good place to start, since it covers most of the basics (cout, cin, opening files, etc). Is there a way to have the code open a terminal window similar to the one opened when I compile and run from sublime text?
I have tried this so far, but it hasn't changed anything.
string cmd = "gnome-terminal-x sh-c 'ls-l; exec bash'";
system(cmd.c_str());
Essentially, I would like to be able to run the program by clicking the .exe, and have the terminal where all of the input and output goes pop up.
You don't need to write any code, you just need to configure the shortcut to launch the program in a terminal. Here's a Gnome dialog that shows that option:
Problem seems to be gnome-terminal, or then just my failure to give it the right arguments. For example gnome-terminal -x sh -c 'ls -l ; exec bash' from command line in another terminal just opens an empty gnome-terminal and spits out a bunch of glib warnings to original terminal... (Note to readers: if you can give the right command that works for gnome-terminal, please let me know in comments or just edit this paragraph.)
However, using xterm works, for example xterm -e sh -c 'ls -l; exec bash', or a line for your code:
string cmd = "xterm -e sh -c 'ls -l; exec bash'";
As a side note, the command to open the default x terminal window of the DE is x-terminal-emulator, but it quite often has the practical problem of different terminals taking different arguments, so sadly you're probably better of using a specific terminal, like that xterm, and requiring that to be installed, or letting user to configure what terminal to use, with what arguments (though letting user to specify any command to be run can also be a security risk, if user is not always trusted).
Just be very careful with escaping. For example, when you test the command form command line, and then copy-paste it to C++ string literal, you need to escape every " and \ one more time for C++. If you have trouble with this, check out C++11 raw strings.
Escaping becomes extra important if you construct the command string at runtime, and especially if you accept user input and add that to the string. In that case, better search for and use some existing library like GLib, or sanitize the user input very carefully (ie. just paranoidically reject anything with chars, which may have a special meaning in shell in some context).
If you are actually asking, how can my program open a console window for itself similar to how Windows console programs behave, and redirect it's own stdin, stdout and stderr there, as if it was launched from command line, that that is not very easy from the same binary, and it is not commonly done like that in Unix.
If you want a behaviour like that, you could create a desktop shortcut, but more general way is to write a wrapper shell script, which starts your binary in a terminal. What kind of script exactly, depends on how you want it to behave exactly: what will it do with stdio, will it return or wait for program to exit, how do you want it to find the binary, how does it behave when run from command line instead of double-clicking from GUI, etc.
I have built a bash script to start up some processes in my system. It simply calls the process and associated config file. Same as I would call from the command line.
#!/bin/bash
# Start specified process in a new session
setsid $1 &>/dev/null &
So to start up someprocess, I would call from the command line:
root#supercomputer:~# start someprocess
This works like a charm. Every process, every time. But when I make a system call from a different running C++ process, someprocess never starts up.
system( "start someprocess" )
This approach for 90% of my processes, except for one. The only difference in the working and not working processes is that the non-working one uses proprietary libraries underneath. I recently added the setsid option to the bash script in hopes that starting a new session would help, but it made no difference. I've also tried popen, and execv. No change.
So my question is what is the difference between calling something with system() and just making that same call from the command line?
All processes are written in C++ on Linux.
.bashrc is only invoked if bash is run as interactive, non-login shell. If it's invoked as non-interactive shell, as when using system() on a script with a bash shebang, it only reads the configuration file pointed to by $BASH_ENV.
That means you have the following options:
add -l to the shebang - causes the shell to read ~/.profile at startup
set $BASH_ENV to the script you want sourced before calling system()
add -i to the shebang - invokes bash as interactive shell and causes it to read ~/.bashrc, but will also effect how bash handles input/output.
I'd recommend the first option.
You can find a detailed explanation of how bash reads it's startup files here. I'm not sure this will solve your problem completely, but it may at leas shed some light on that part of the issue.
Check the environment variables that are used in the system() call. For example, call system to print out some of the variables, and see if they match what you see from the command line.
Likely they are not being sourced correctly.
I tried the following code, to communicate with the command line from c++ code.
#include<iostream>
#include<cv.h>
int main()
{
system("gnome-terminal");
system("cd");
}
The gnome-terminal command is executing fine. After I close the terminal, when am expecting the cd to execute, however, is not happening. Could you please help me and point out the reason? Thanks. I was expecting the function to make the cmd go down to the home directory
, but it did not. am working in linux
I tried it even by removing gnome. simple cd is not working. am I doing something rong>?
If I try ls, it seems to be working fine!
My main aim is to open a new terminal, and execute commands on that new terminal through the present program that opened the new terminal. Could you please tell me how I can achieve this??
If you want to run a program and wait for it to finish before executing next line, take a look at this page and example code here: http://www.thegeekstuff.com/2012/03/c-process-control-functions/
But if you want to run gnome-terminal and execute a command in newly created window, do this:
system("gnome-terminal -x sh -c 'cd /tmp ; ls -la'");
The system function creates a shell child process to execute the specified command.
cd is a shell command which changes the current working directory of that shell process only.
So the child's cd probably works fine, but it has no effect on your C++ program, which is a different process.
Instead, you probably want to look at the Linux system call chdir.
Thanks for your help!! This command worked perfectly fine from this link
https://superuser.com/questions/198015/open-gnome-terminal-programmatically-and-execute-commands-after-bashrc-was-execu
gnome-terminal -x sh -c 'command1; command2; exec bash'
and I entered the respective commands in the new window. But to change the working directory in the shell am working o, I haven't still figured that out.