I am trying to find out if a command line program is installed, so that it can be used later.
So far what I have tried is:
int whichReturn = system("command -v THE_CL_PROGRAM >/dev/null && { exit 50; }|| { exit 60; }");
if (whichReturn == 12800) { //system 'apparently' returns the return value *256 (50*256 = 12800)
//...
}
However it seems that it always returns 60 and so fails.
Is there an easier way to do this? Or can someone point out where my mistake is please?
Thanks
A complete program using which:
isthere.cpp:
#include <iostream>
#include <cstdlib>
#include <sstream>
int main(int argc, char* argv[])
{
std::ostringstream cmd;
cmd << "which " << argv[1] << " >/dev/null 2>&1";
bool isInstalled = (system(cmd.str().c_str()) == 0);
std::cout << argv[1] << " is "<< ((isInstalled)?"":"NOT ") << "installed! << std::endl;
}
Output:
$ ./isthere ls
ls is installed!
$ ./isthere grep
grep is installed!
$ ./isthere foo
foo is NOT installed!
Related
In cpp, I need to run a program like this
g++ *.cpp -o out
./out <input.txt> <somenumber>
where input.txt is a text file containing lines of information I need to proccess, and somenumber is an integer value I need to use.
I am searching for hours and couldn't find the answer I was looking for,
I found solutions that work like
./out < input.txt
reads the input.txt line as a string which then in the code I can process,
but the assignment says that the code will be run only and specifically as
./out <input.txt> <somenumber>
can anyone help ?
I have wrote some code, in which I wrote my main as
int main(int argc, char* argv[] ){
but when I run
./out <input.txt>
the terminal gives an error saying
" -bash: syntax error near unexpected token `newline' "
edit: typo
You are correct in wanting to accomplish this using argc and argv. Something like this should work
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
std::string file_name;
std::string number;
if(argc == 3) {
file_name = argv[1];
number = argv[2];
}
std::cout << "Filename: " << file_name << " number: " << number << "\n";
}
By convention, the use of < > to enclose an input parameter signifies that the parameter is mandatory for the command.
Therefore, the command
./out <input.txt> <some_number>
signifies that the two parameters - input.txt and some_number are mandatory.
The command can be run as:
./out input.txt 101
Here is an example of working code:
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
string inputFile;
string someNumber;
if(argc != 3) {
cout << "Sorry! Wrong input \n";
cout << "Usage: ./out <input_file_name> <some_number> \n";
return -1;
}
inputFile = argv[1];
someNumber = argv[2];
cout << "Processing ...\n";
cout << "File = " << inputFile << ", Number = " << someNumber << "\n";
return 0;
}
Output:
$ ./out input.txt 101
Processing ...
File = input.txt, Number = 101
Aim: To design a linux shell, which shows a prompt to take input from user, creates a new process to execute that command then terminates/exits the process. Here is my code
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
using namespace std;
string cmd; //global string so cmd copied to child to execute
void HandleAsParent(){
cout<<"Linux Shell 1.0\n";
string s;
while (!exitflag) {
cout<<"myShell>";
getline(cin,cmd); //Take user input
fork();
wait(NULL);
}
}
void HandleAsChild(){
cout<<"Executing";
system(cmd.c_str());
}
int main() {
pid_t p = fork();
if(p != 0){
HandleAsParent(); //This is parent process
}
else {
HandleAsChild(); //This is child process
}
}
The problem is that, because of the first fork() call in the main,
myShell>Executing
is displayed on the first line when the program runs instead of just
myShell>
.
I am able to understand why this is happening but cannot figure out how do I stop that first child process from being executed.
Please suggest me workarounds/solutions to my problem.
Edit 1: This is one of my Assignment(for learning UNIX Processes)
questions, and It is clearly stated that the program " prompts the
user for a command, parses the command, and then executes it with a
child process "
As I already guessed, system() probably uses a combination of fork(), exec() and wait(). Out of curiosity, I googled for source code and found one on woboq.org: glibc/sysdeps/posix/system.c.
This in mind, using system(), the required child process "comes for free". So, I got this minimal sample:
#include <iostream>
void callCmd(const std::string &cmd)
{
system(cmd.c_str());
}
int main()
{
std::cout << "My Linux Shell 1.0\n"
<< "Type exit[Enter] to exit.\n";
for (;;) {
std::cout << "> ";
std::string input; std::getline(std::cin, input);
if (input == "exit") return 0;
callCmd(input);
}
}
Compiled and tested on cygwin on Windows 10:
$ g++ -std=c++11 -o mycroShell mycroShell.cc
$ ./mycroShell
My Linux Shell 1.0
Type exit[Enter] to exit.
> echo "Hello"
Hello
> exit
$
After getting this running, the system() call in callCmd() can be replaced by fork()/exec()/wait() without the necessity to change anything else.
A simplified version could look like this:
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void callCmd(const std::string &input)
{
// the pre-processing: split the input into command and arguments
std::string cmdArgs = input;
std::vector<char*> args;
char *cmd = &cmdArgs[0];
args.push_back(cmd);
for (char *c = cmd; *c; ++c) {
if (*c == ' ') {
*c = '\0'; args.push_back(c + 1);
}
}
args.push_back(nullptr); // append terminator
// simple replacement of system() (not that sophisticated)
int ret = fork();
if (ret < 0) { // failure
std::cerr << "Failed to execute '" << cmd << "'!\n";
} else if (ret == 0) { // child
execvp(cmd, args.data());
} else { // parent
waitpid(ret, nullptr, 0);
}
}
int main()
{
std::cout << "My Linux Shell 1.1\n"
<< "Type exit[Enter] to exit.\n";
for (;;) {
std::cout << "> ";
std::string input; std::getline(std::cin, input);
if (input == "exit") return 0;
callCmd(input);
}
}
Compiled and tested on cygwin on Windows 10 again:
$ g++ -std=c++11 -o mycroShell mycroShell.cc
$ ./mycroShell
My Linux Shell 1.1
Type exit[Enter] to exit.
> /usr/bin/echo "Hello"
"Hello"
> exit
$
Notes:
IMHO, the most tricky part of this is to prepare a proper argument vector for execvp.
I tried with echo "Hello" as well and it worked. This surprised me a bit as echo is a bash built-in command. I assume that it found /usr/bin/echo and used it as well as in my above output.
The error handling is rather poor – something which should be extended for serious applications.
I want to create a c++ app for ubuntu 16.04 that retrieves data from folder /sys/class/net/eth0/statistics/. Specifically I need to get rx_bytes and rx_packets. The command that I have tried succesfully in terminal is the following:
sed -n -e 3p -e 13p /sys/class/net/enp0s3/statistics/*
I tried to give the same command using Poco ProcessHandle method using the following code:
#include <iostream>
#include <vector>
#include "Poco/Exception.h"
#include "Poco/Process.h"
#include "Poco/Pipe.h"
#include "Poco/PipeStream.h"
using namespace std;
using Poco::Process;
using Poco::ProcessHandle;
using Poco::Pipe;
using Poco::PipeInputStream;
using Poco::PipeOutputStream;
using Poco::Exception;
int main(int argc, char** argv)
{
try {
std::vector<std::string> args;
std::string cmd = "sed";
args.push_back("-n");
args.push_back("-e");
args.push_back("3p");
args.push_back("-e");
args.push_back("15p");
args.push_back("/sys/class/net/enp0s3/statistics/*");
Pipe outPipe;
ProcessHandle ph = Process::launch(cmd, args, 0, &outPipe, 0);
PipeInputStream istr(outPipe);
std::string s;
int c = istr.get();
while (c != -1) {
s += (char)c;
c = istr.get();
}
std::cout << "string is " << s << std::endl;
return 0;
}
catch (Poco::Exception& exc)
{
std::cerr << exc.displayText() << exc.code() << string(exc.name()) << std::endl;
return 1;
}
However I get the error message:
sed: can't read /sys/class/net/enp0s3/statistics/*: No such file or directory
When I try the code with a specific file I get the correct strings.
I know that there is the command cat alternative but is there any way for the above code to work succesfully.
I have been using code similar to this example to get the results to Linux shell commands from within C++. It seems to work great with basic commands. However, when I try to run it with the command in the example I get the shell error: syntax error near unexpected token `('
#include <stdio.h>
#include <iostream>
int main(int argc, char *argv[]) {
std::string cmdString = "cat <(grep 'cpu ' /proc/stat) <(sleep 1 && grep 'cpu ' /proc/stat) | "
"awk -v RS=\"\" '{print ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5) }' 2>&1";
std::string result, file;
FILE *stream;
std::cout << "cmdString = " << cmdString << std::endl;
stream = popen(cmdString.c_str(), "r");
char buffer[256];
if(fgets(buffer, sizeof(buffer), stream) != NULL) {
file = buffer;
result += file.substr(0, file.size() - 1);
}
pclose(stream);
std::cout << "result = " << result << std::endl;
return 0;
}
Am I doing something wrong? Do I need to reformat the string somehow?
You are using bash-specific constructs in your command line. POSIX mandates that the argument of popen is passed to bin/sh, not user's current shell.
To fix the problem you can do one of the following:
Rewrite the commands to be /bin/sh-compliant.
Explicitly use bash in your command line:
std::string cmdString = "bash -c \".....\"";
Drop the shell altogether and implement the pipeline yourself.
I was wondering if you could have it so when you go and click on a program in linux it always automatically brings up the command line for the information being displayed or if I decided to use ncurses for an interface. If so is this a system specific call or can you do this with ncurses? Because half of my program is going to be via terminal.
Thanks
Since nitt wouldn't let me amend his code snippet, I'm posting a corrected snippet in case anyone would like to use it:
#include <cstdio>
#include <unistd.h>
#include <iostream>
int main(int argc, char* argv[])
{
if (isatty(0))
{
std::cout << "Hello, World!" << std::endl;
for (int i=0; i<argc; i++)
std::cout << "arg: " << i << "\t" << argv[i] << std::endl;
std::cout << "Press return to continue . . ." << std::flush;
std::cin.get();
}
else
{
const char* args[argc+3], **it=args;
*it++ = "gnome-terminal";
*it++ = "-x";
it = std::copy(argv, argv+argc, it);
*it++ = 0;
if (-1 == execvp("gnome-terminal", (char* const*) &args[0]))
perror("exec");
}
}
Yes, just invoke a terminal with your app in it. For example:
rxvt -e myapp
Starts a terminal running your app. You could also use xterm. If you want to use wide chars/unicode I recommend rxvt-unicode.
You can put this in a .desktop file with an icon defined there, and then that will be placed in the system menu.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int fileExists(string x321) {
ifstream x123 (x321.c_str());
string x213;
x123 >> x213;
if (x213 == "") {
return false;
} else {
return true;
}
}
int createConsole(string fname) {
if (fileExists("~tmp") == false) {
ofstream tmp ("~tmp");
tmp << "tmpfile";
fname = "gnome-terminal -e " + fname;
system(fname.c_str());
system("exit");
return 0;
}
remove("~tmp");
return 1;
}
int main(int argc, char** args) {
createConsole(args[0]);
cout << "Hello, World!" << endl;
cout << "Press return to continue . . .";
cin.get();
}
Pay attention to the "createConsole" and "fileExists" function. I wrote this myself.