I'm trying to create a simple script on my server, basically I would like to sent a string and display it via system function...
#include <stdio.h>
int main()
{
char txt[100];
printf("Insert a text: ");
fgets(txt, 100, stdin);
system("echo %s"), txt;
return 0;
}
Rght now I'm not getting any string just "%s"
any idea why?
system("echo %s"), txt;
This isn't doing what you think; it's an expression which evaluates to txt. Since evaluating txt has no side effects, and since you're not capturing the result of the expression anywhere, adding , txt after the system call essentially does nothing. See this question for some information on the "comma"-operator in C.
Moreover, system doesn't support the use of printf-style format specifiers, so the %s in your string literal doesn't have any special meaning; it's just going to be echoed exactly as written, as you've seen. If you want to construct a command at runtime for use with system, you will have to do so with sprintf or similar.
The prototype to system() is:
int system(const char * command);
From man 3 system:
executes the shell command specified in command
From this we can safely assume s refers to a C-"string".
So prepare the string using for example snprintf():
char s[1024];
snprintf(s, 1024 -1, "echo %s", txt); /* -1 for the C-"string"'s 0-terminator */
Then pass it:
system(s);
Instead of system("echo %s"), txt; try this:
printf("%s", txt);
the system statement will not format the output, like printf.
suggest using:
#include <stdio.h>
#include <stdlib.h> // system()
#include <string.h> // strcpy(), strcat()
#define BUF_LEN (100)
int main()
{
char output[10+BUF_LEN] = "echo ";
char txt[BUF_LEN] = {'\0'};
printf("Insert a text: ");
fgets(txt, BUF_LEN, stdin);
strcat( output, txt );
system( output );
return 0;
}
The above code works very nicely, however;
do not include any command separators, semicolons, or other characters that would be interpreted by the shell in the input string.
Related
For e.g i have the following program in windows.
#include <stdio.h>
int main(int argc, char *argv[]) {
char *input = argv[1];
printf("your input: %s", input);
return 0;
}
When i run a cmd shell and invoke
C:\>whoami | main.exe
i get as output
your input: (null)
The first argument argv[0] (the filename itself) is passed correct. How to receive the output of whoami as input to my program?
Edit: Since people mostly ask for code if you ask a question, i will also provide code in my answer. Just to be fair. The solution i use (thanks to Gerardo Zinno) is to read from stdin - so i use scanf.
char input[1024] = {0};
read(STDIN_FILENO, input, 1024);
input[strcspn(input, "\n")] = '\0';
printf("you wrote: %s", input);
return 0;
You have to read from the stdin just like if the input was coming from a user typing in the terminal. The pipe will send (link) the stdout of whoami to the stdin of your program.
There are many options to read from the stdin. You can use fread with stdin as last parameter, scanf, fscanf(stdin,...),...
Simple program: reads a name and a surname (John Smith) from a .txt file via fscanf, adds spaces, prints the name in the console (just as it's written in the .txt).
If compiled and ran on Win10 via
Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26433 for x86
the following code does not produce the same output for the same input across different .exe launches (no recompiling). For each input it seems to have multiple outputs avaialble, between which the program decides at random.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input_file_name[255];
FILE * input_file;
char name[255];
input_file = fopen ("a.txt","r");
do
{
if (strlen(name) != 0 )
name[strlen(name)] = ' ';
fscanf (input_file, "%s", name + strlen(name) * sizeof(char));
}while(!feof(input_file));
fclose (input_file);
printf("Name:%s\n", name);
system("pause");
return 0;
}
I will list a couple of inputs and outputs for them. As not all characters are printable, I will type type them as \ascii_code instead, such as \97 = a.
The most common anomalies are \31 (Unit Separator) added at the very front of the string and \12 (NP form feed, new page) or \17 (device control 1) right before the surname (after the first space).
For "John Smith":
"John Smith" (proper output)
"\31 John Smith"
For "Atoroco Coco"
"Atoroco \12Coco"
"\31 Atoroco \16Coco"
For "Mickey Mouse"
"Mickey Mouse" (proper)
"\31 Mickey\81Mouse" (There is a \32 (space) in the string right before the \81, but the console doesn't show the space?!)
If compiled a different machine (MacOS, compiler unknown) it seems to work properly each time, that is it prints simply the .txt's contents.
Why are there multiple outputs produced, seemingly at random?
Why are these characters (\31, \12 etc) in particular added, and no other?
Your code invokes Undefined Behavior (UB), since it uses name uninitialized. Read more in What is Undefined Behaviour in C?
We will initialize it, and make sure the null terminator is there. Standard string functions, like strlen(), depend on the null terminator to mark the end of the string.
Then, you need to make sure that you read something before you call feof(). Moreover, it's a good idea to check what fscanf() returns, which denotes the number of items read.
Putting all together, we get:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input_file_name[255];
FILE * input_file;
char name[255] = "\0"; // initialize it so that is has a null terminator
input_file = fopen ("a.txt","r");
do
{
if (strlen(name) != 0 )
name[strlen(name)] = ' ';
} while (fscanf (input_file, "%s ", name + strlen(name) * sizeof(char)) == 1 && !feof(input_file));
fclose (input_file);
printf("Name:%s\n", name);
return 0;
}
Output (for "georgios samaras"):
georgios samaras
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)
For some reason, execvp() doesn't find the commands (like ls, pwd, etc.) in my PATH file, which includes /bin. Since I have a customized terminal alias with ls, I'm using pwd, etc. to test (as well as a fresh Linux machine), but I keep getting this for the output:
gcc main.c
./a.out
What would you like to do?
ls
arg[0]: ls
arg[1]: (null)
arg[2]: (null)
arg[3]: (null)
arg[4]: (null)
arg[5]: (null)
arg[6]: (null)
arg[7]: (null)
arg[8]: (null)
arg[9]: (null)
before exec
after exec
ERROR: No such file or directory
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/*
Write a c program that runs a command line program with exactly one command line argument. It should work as follows:
Prompts the user for a program to run via the command line.
Reads in that line (using fgets) and parses it to be used by one of the exec functions.
Runs the command using exec
You do not need to fork off a separate process and wait, the purpose of this assignment is only to parse a single line of input and run a program once.
*/
int main() {
printf("\nWhat would you like to do?\n");
char* input = malloc( 100 ); //100 character string for input
fgets(input, 100, stdin); //reads from stdin (terminal input "file")
//parses command in input (max of 8 flags)
int number_of_args = 10;
char *args[number_of_args];
//puts cmd && flags in args
int i = 0;
for(; i < number_of_args; i++) {
args[i] = strsep( &input, " ");
printf("arg[%i]: %s\n", i, args[i]);
}
args[number_of_args - 1] = 0; //last element for execvp must be NULL;
// printf("nullify final index -> args[%i] = %s\n", number_of_args - 1, args[number_of_args -1]);
printf("before exec\n");
int e = execvp( args[0], args);
printf("after exec\n");
if(e < 0)
printf("ERROR: %s\n", strerror(errno));
return 0;
}
EDIT: Thought it'd be good to include my PATH as well:
echo $PATH
/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
fgets() reads in the newline character if there's space available in the buffer. So when you input ls, it's actually ls\n. Obivously, execvp() can't find such a command and it fails. So the solution is to remove the trailing newline, if any.
char *p = strchr(input, '\n');
if (p) *p = 0;
You should also use argc for argument processing (if you read in the commands and arguments via main()'s argument) rather than assuming some fixed numbers. Or simply break the loop when strsep() returns NULL the first time. Technically, your code invokes undefined behaviour when you print all those null strings.
First of all, I know there is a question with an identical name, however it deals with c++ and not c.
Is there any way to set a string to the clipboard in c?
This is the mentioned question if anyone is curious, even though it is for windows.
I need it to be in c because I am writing a program in c, and I would like to copy a string to the clipboard.
printf("Welcome! Please enter a sentence to begin.\n> ");
fgets(sentence, ARR_MAX, stdin);
//scan in sentence
int i;
char command[ARR_MAX + 25] = {0};
strncat(command, "echo '",6);
strncat(command, sentence, strlen(sentence));
strncat(command, "' | pbcopy",11);
command[ARR_MAX + 24] = '\0';
i = system(command); // Executes echo 'string' | pbcopy
The above code is saving 2 new lines in addition to the string. ARR_MAX is 300.
you tagged your question for osx. so this should be sufficient:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PasteboardGuide106/Articles/pbCopying.html#//apple_ref/doc/uid/TP40008102-SW1
however there is the problem of having to call non-native c. Whether this is directly possible I don`t know.
if you can accept some hacky behavior you could invoke the pbcopy command.
http://osxdaily.com/2007/03/05/manipulating-the-clipboard-from-the-command-line/
this would be very easy to implement. here is a short function which should copy to clipboard. But I dont have osx handy so cannot test myself
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int copytoclipboard(const char *str) {
const char proto_cmd[] = "echo '%s' | pbcopy";
char cmd[strlen(str) + strlen(proto_cmd) - 1]; // -2 to remove the length of %s in proto cmd and + 1 for null terminator = -1
sprintf(cmd ,proto_cmd, str);
return system(cmd);
}
int main()
{
copytoclipboard("copy this to clipboard");
exit(0);
}