All right, so there are many GUI's written for popular command-line only programs on Linux; they're written for Nmap, Memtest, etc.
So I have 2 questions:
1. What languages allow you to do this.
2. And, quite simply: how?
I know that in C++ there are "SYSTEM" commands that allow you to utilize various system calls, but can this be used to directly take user imput and turn that into something put into the command line?
[Linux] Passing Commands to Shell?
Moderator: Coders of Rage
[Linux] Passing Commands to Shell?
and sometimes there’s a third, even deeper level and that one is the same as the top surface one...Like with pie…
-Dr Horrible
-Dr Horrible
- Ginto8
- ES Beta Backer
- Posts: 1064
- Joined: Tue Jan 06, 2009 4:12 pm
- Programming Language of Choice: C/C++, Java
Re: [Linux] Passing Commands to Shell?
here's a code snippet for a way to take and execute shell commands (should work on all OS's):
Code: Select all
string command = "";
std::cout << "Enter command: ";
getline(std::cin, command);
system(command.c_str());
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
Re: [Linux] Passing Commands to Shell?
It's really as simple as making a "system" call?Ginto8 wrote:here's a code snippet for a way to take and execute shell commands (should work on all OS's):Code: Select all
string command = ""; std::cout << "Enter command: "; getline(std::cin, command); system(command.c_str());
So I could do this?
Code: Select all
system("mkdir /xyz");
and sometimes there’s a third, even deeper level and that one is the same as the top surface one...Like with pie…
-Dr Horrible
-Dr Horrible
- M_D_K
- Chaos Rift Demigod
- Posts: 1087
- Joined: Tue Oct 28, 2008 10:33 am
- Favorite Gaming Platforms: PC
- Programming Language of Choice: C/++
- Location: UK
Re: [Linux] Passing Commands to Shell?
I think he is talking about piping input and output through a GUI.
Gyro Sheen wrote:you pour their inventory onto my life
IRC wrote: <sparda> The routine had a stack overflow, sorry.
<sparda> Apparently the stack was full of shit.
- MarauderIIC
- Respected Programmer
- Posts: 3406
- Joined: Sat Jul 10, 2004 3:05 pm
- Location: Maryland, USA
Re: [Linux] Passing Commands to Shell?
"I think he is talking about piping input and output through a GUI."
I have code for this that might be applicable. It's not the best, but it works. This can actually be run as a shell, although functionality is limited.
Essentially you might be looking looking for execvp, or execlp if you want to hard-code parameters.
Code dump:
shell.c (main):
run.c
process.c
input.c
defs.h
input.h
process.h
run.h
I have code for this that might be applicable. It's not the best, but it works. This can actually be run as a shell, although functionality is limited.
Essentially you might be looking looking for execvp, or execlp if you want to hard-code parameters.
Code dump:
shell.c (main):
Code: Select all
/************************************************************************
* Created by Steven A. Wilson *
* CS 470-001 S'08 Assignment 4 *
* This is a basic command interpreter for Linux *
* Specifications: *
* + Supports background processing *
* + Supports MAX_INPUT input chars and MAX_ARGS process arguments *
* + Supports chained pipes up to MAX_PS *
* + Supports output to single file *
***********************************************************************/
#include "run.h"
#include "input.h"
#include "defs.h"
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
const char* EXIT_STR = "exit";
const char* QUIT_STR = "quit";
const char PROMPT[] = "shell> ";
const char DELIMS[] = ">|";
char actual_input[MAX_INPUT]; //Stores the user's input
char tokenize[MAX_INPUT]; //A copy of actual_input that we run strtok on
char buffer[MAX_INPUT]; //A modifiable copy of current input btwn DELIMs
char* pipe_input; //Pointer past the next DELIM
char* input; //The current input between DELIMs
size_t psi = 0; //process index
//Initialize list of processes
Process* ps_queue[MAX_PS];
for (int i = 0;i < MAX_PS;++i)
ps_queue[i] = NULL;
Process* cur_ps = ps_queue[psi];
Process* prev_ps = NULL;
//Get input from the user, tokenize it on pipe characters.
//If there are no pipes, parse the whole line.
//We have to copy the whole thing because split_str also calls strtok
get_input(PROMPT, actual_input, MAX_INPUT);
strncpy(tokenize, actual_input, MAX_INPUT);
pipe_input = strtok(tokenize, DELIMS);
input = (pipe_input) ? pipe_input : tokenize;
while ( strlen(input) == 0 ||
((strncmp(input, EXIT_STR, MAX_INPUT) != 0) &&
(strncmp(input, QUIT_STR, MAX_INPUT) != 0)) )
{
trim_str(input);
prev_ps = cur_ps;
cur_ps = ps_queue[psi] = init_ps(alloc_ps());
//Copy our working input to buffer so we can modify it w/o modifying
//the actual_input
strncpy(buffer, input, MAX_INPUT);
//trim_str(buffer);
cur_ps->background = (buffer[strlen(buffer)-1] == '&');
//Cut off the '&' if we're running in background.
//Not storing size_t strlen(input)-1 because bkgd is uncommon
if (cur_ps->background)
buffer[strlen(buffer)-1] = '\0';
if (input-1 > 0)
cur_ps->file = (*(input-1) == '>');
split_str(cur_ps->argv, buffer, " ", MAX_ARGS);
//Move our point of reference (re: the pipe & fd), if applicable
set_pipes(cur_ps, prev_ps);
//Since split_str also calls strtok, we need to redo this
//Must recopy because apparently strtok does something to the original
strncpy(tokenize, actual_input, MAX_INPUT);
pipe_input = strtok(tokenize, DELIMS);
//Advance one past our current token
for (int tok_track = 0;tok_track <= psi;++tok_track)
pipe_input = strtok(NULL, DELIMS);
if (prev_ps && prev_ps->file) {
printf("shell: Parse error: Cannot redirect after first '>>'\n");
free_all(ps_queue, MAX_PS);
pipe_input = NULL;
} else if ( prev_ps && (cur_ps->background || prev_ps->background) ) {
printf("shell: Parse error: Cannot use '&' with '|' or '>>'.\n");
free_all(ps_queue, MAX_PS);
pipe_input = NULL;
}
//This process has been totally initialized.
//Move on to the next.
if (!pipe_input) { //No more processes to move on to
run_all(ps_queue, MAX_PS);
free_all(ps_queue, MAX_PS);
cur_ps = NULL;
prev_ps = NULL;
psi = 0;
//Reset our user input buffer
memset(actual_input, '\0', sizeof(actual_input));
//Get new input and the initial pipe val
get_input(PROMPT, actual_input, MAX_INPUT);
strncpy(tokenize, actual_input, MAX_INPUT);
pipe_input = strtok(tokenize, DELIMS);
} else {
//Continue tokenization
psi++;
}
input = (pipe_input) ? pipe_input : tokenize;
}
return 0;
}
Code: Select all
/**********************
* run.c
* Steven A Wilson - CS 470
* Part of shell
* Contains function definitions for running a parsed command
*********************/
#include "run.h"
#include "process.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h> //file i/o
#include <sys/fcntl.h> //file i/o
/*
* Handles the forking and does the exec call, etc
* argv follows standard argv practice (prog is argv[0])
* background determines whether or not parent waits for completion
*/
bool run(Process* ps, int ps_index) {
if (ps == NULL)
return false;
const char CHILD_ERROR_PREFIX[] = "shell: Execution error";
const char PARENT_ERROR_PREFIX[] = "shell: Wait error";
//Options to call a wait but not actually wait for it
//Used on background child processes
const int NOWAIT_OPTIONS = WNOHANG | WUNTRACED | WCONTINUED;
static int fds[MAX_PS][2];
const bool do_pipe = (ps->pipe_right || ps->pipe_left);
const int input_index = ps_index-1;
const int output_index = ps_index;
//Only open the pipe once.
//Every process opens its output pipe
//Input pipe is one less than the output pipe
if (ps->pipe_right && !ps->file) {
if (pipe(fds[output_index]) == -1) {
perror("pipe");
return false;
}
}
int pid = fork();
if (pid > 0) { //Parent
ps->pid = pid;
if (!do_pipe) {
if (!ps->background) {
if (waitpid(pid, NULL, 0) == -1) {
perror(PARENT_ERROR_PREFIX);
return false;
}
} else {
//If we don't do a wait on all child
//processes, they become zombies
if (waitpid(pid, NULL, NOWAIT_OPTIONS) == -1) {
perror(PARENT_ERROR_PREFIX);
return false;
}
}
} else {
for (int i = 0;i <= input_index;++i) {
close(fds[i][0]);
close(fds[i][1]);
}
//Wait for the last child to finish
if (ps->pipe_left && !ps->pipe_right)
waitpid(ps->pid, NULL, 0);
}
} else if (pid == 0) { //Child
//Get our input from the pipe
if (ps->pipe_left) {
dup2(fds[input_index][0], 0);
close(fds[input_index][1]);
/*
* Don't close unused output pipes here because
* it makes the program freak out.
* */
}
//Send our output to the pipe
if (ps->pipe_right) {
if (ps->file) {
printf("shell: Parse error: Cannot have '|' after '>>'\n");
close(fds[input_index][0]);
close(fds[input_index][1]);
getchar();
exit(EXIT_FAILURE);
}
dup2(fds[output_index][1], 1);
close(fds[output_index][0]);
if (!ps->pipe_left && input_index >= 0) {
close(fds[input_index][0]);
close(fds[input_index][1]);
}
}
if (ps->file)
fds[output_index][1] = creat(ps->argv[0], 0600);
if (!ps->file) {
execvp(ps->argv[0], ps->argv);
} else {
char buff;
if (fds[output_index][1] != -1) {
while (read(fds[input_index][0], &buff, 1) > 0)
write(fds[output_index][1], &buff, 1);
close(fds[output_index][1]);
exit(EXIT_SUCCESS); //Prevent fall-through to perror
}
}
printf("\n");
//This will only be hit if execvp() or creat() fails.
perror(CHILD_ERROR_PREFIX);
if (!ps->file) {
printf("%s (cont): while attempting to execute '%s'\n",
CHILD_ERROR_PREFIX, ps->argv[0]);
} else {
printf("%s (cont): while attempting to write to '%s'\n",
CHILD_ERROR_PREFIX, ps->argv[0]);
}
exit(EXIT_FAILURE); //Kill the child
} else { //Error
if (ps->pipe_left || ps->pipe_right) {
close(fds[input_index][0]);
close(fds[output_index][1]);
}
printf("%s: fork failed\n", CHILD_ERROR_PREFIX);
return false;
}
return true;
}
Code: Select all
#include "process.h"
#include "run.h"
#include <string.h> //memset
#include <stdlib.h> //malloc
#include <stdio.h> //printf debug
//Set initial values for a process, returns a pointer to it.
Process* init_ps(Process* ps) {
if (!ps)
return NULL;
for (int i = 0;i < MAX_ARGS;++i)
ps->argv[i] = NULL;
ps->background = false;
ps->pipe_right = false;
ps->pipe_left = false;
ps->file = false;
return ps;
}
//Allocate a new process, return a pointer to it
Process* alloc_ps() {
Process* ps = (Process*) malloc( sizeof(Process) );
if (ps == NULL) {
printf("Failure allocating memory for process.\n");
exit(EXIT_FAILURE);
}
return ps;
}
//Set cur_ps as being on RHS of a pipe and prev_ps as being on LHS of a pipe
//If either are null, abort
void set_pipes(Process* cur_ps, Process* prev_ps) {
if (!cur_ps || !prev_ps)
return;
cur_ps->pipe_left = true;
cur_ps->pipe_right = false;
prev_ps->pipe_right = true;
}
//Runs num_ps ps's processes in arr
void run_all(Process** arr, size_t num_ps) {
if (!arr || arr[0] == NULL)
return;
Process* ps;
for (int i = 0;i < num_ps; ++i) {
ps = arr[i];
if (!ps)
break;
run(ps, i);
}
}
//Frees num_ps ps's processes in arr
void free_all(Process** arr, size_t num_ps) {
if (!arr || arr[0] == NULL)
return;
Process* ps;
for (int i = 0;i < num_ps;++i) {
ps = arr[i];
if (!ps)
break;
for (int j = 0;j < MAX_ARGS && ps->argv[j];++j)
free(ps->argv[j]);
free(ps);
arr[i] = NULL;
}
}
Code: Select all
/**********************
* input.c
* Steven A Wilson - CS470
* Part of shell
* Contains function definitions for parsing user input
*********************/
#include "input.h"
#include "defs.h"
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
//Modifies str, replacing \r\n with \0\0
void strip_rn(char str[]) {
char* found_endline;
//Directly modify str
found_endline = strchr(str, '\n');
if (found_endline)
*found_endline = '\0';
found_endline = strchr(str, '\r');
if (found_endline)
*found_endline = '\0';
}
/*
* Splits a string on first occurence of 'on'
* Returning results to before and after, neither
* containing 'on'
*/
void split_str(char** result, char* input, const char* delims, size_t max_args)
{
if (!input) {
result[0][0] = '\0';
return;
}
size_t i;
char* cur_token = strtok(input, delims);
//Previous result wasn't NULL
for (i = 0;i < max_args && cur_token != NULL;++i) {
result[i] = (char*)malloc(MAX_INPUT);
strncpy(result[i], trim_str(cur_token), MAX_INPUT);
cur_token = strtok(NULL, delims);
}
//Set the NULL result or final result to \0
result[i] = NULL;
}
/*
* Trims spaces off of start and end of a string
*/
char* trim_str(char* str) {
char ptr[strlen(str)+1];
int i, j = 0;
bool lead = false;
//Remove leading spaces, copy everything else.
for (i = 0; str[i] != '\0';++i) {
if (lead) {
ptr[j++] = str[i];
} else if (str[i] != ' ' && !lead) {
ptr[j++] = str[i];
lead = true;
}
}
ptr[j] = '\0';
//Remove trailing spaces.
while (ptr[--j] == ' ')
ptr[j] = '\0';
strcpy(str, ptr);
str = ptr;
return str;
}
/*
* Prints 'prompt' followed by ": "
* Waits for and stores user input in 'buffer'
* Maximum characters sent to 'buffer' is 'max'
*/
void get_input(const char* prompt, char* buffer, size_t max) {
printf("%s", prompt);
fgets(buffer, max, stdin);
strip_rn(buffer);
}
/*********
* copy_str
* Copies to 'to' from 'from' not including ch
* If ch (+ ch2, if not 0) is not found, copies entire string
* NULL-terminates 'to' if required.
* Returns one past from's ch/ch2, or NULL if not found
********/
char* copy_str(char* to, const char* from, char ch = '|', char ch2 = '\0') {
const int len_to = strlen(to);
const int len_from = strlen(from);
// const int len_match = strlen(match);
char* until = strchr(from, ch);
size_t max;
//Couldn't match or 2nd char is not a match
if (until == NULL || (ch2 && *(until+1) != ch2) ) {
max = (len_to > len_from) ? len_to : len_from;
} else {
max = (size_t)(until - from - 1); //-1: Avoid ch
until++; //Increment for retval: advance past ch
if (ch2)
until++;
}
strncpy(to, from, max);
if (to[max-1] != '\0')
to[max-1] = '\0';
return until;
}
Code: Select all
#ifndef DEFS_H
#define DEFS_H
#define MAX_INPUT 1028
#define MAX_ARGS 128
#define MAX_PS 128
#endif
Code: Select all
/***********************************
* Part of shell
* input.h
* Contains function prototypes for editing user input
***********************************/
#ifndef INPUT_H
#define INPUT_H
#include <sys/types.h>
void strip_rn(char str[]);
void split_str(char** result, char* input, const char* delims, size_t max_args);
void get_input(const char* prompt, char* buffer, size_t max);
char* trim_str(char* str);
#endif
Code: Select all
#ifndef PROCESS_H
#define PROCESS_H
#include "defs.h"
#include "process.h"
#include <sys/types.h>
#ifndef NULL
#define NULL 0
#endif
struct Process {
//int fds[2]; //0 == input, 1 == output
char* argv[MAX_ARGS]; //Standard argv
int pid;
bool background; //There was a & after argv
bool file; //I'm really a file that input is coming to
bool pipe_right; //There was a pipe on the RHS of this input
bool pipe_left; // ..LHS..
};
//Set initial values for a process, returns a pointer to it
Process* init_ps(Process* ps);
//Allocate a new process
Process* alloc_ps();
//If cur_ps and prev_ps, then set cur_ps as being on RHS of pipe and prev_ps
//as being on LHS of pipe.
void set_pipes(Process* cur_ps, Process* prev_ps);
//Runs all processes in arr
void run_all(Process** arr, size_t num_ps);
//Frees all processes in arr
void free_all(Process** arr, size_t num_ps);
#endif
Code: Select all
#ifndef RUN_H
#define RUN_H
#include "process.h"
/* Forks to execute process specified by ps
* Returns true to parent on success
* Returns false ot parent on parent fail
* Exits child on child fail
*/
bool run(Process* ps, int ps_index);
#endif
I realized the moment I fell into the fissure that the book would not be destroyed as I had planned.