I am looking for an example of a simple app that will use printf to express two different strings based on a positional parameter.
In bash I would use:
case $1 in
-h | --help ) showHelp
exit
;;
* ) manPipe
exit 1
esac
And prior to this I would list that a function called showHelp would be called if the operater types either $ foo -h or $ foo -help into the Terminal. Anything else like $ foo -bar would request that the function manPipe would get called.
I have this code so far:
#include <stdio.h>
#include <cstring>
int secretFunction() {
printf("Success! You found the secret message!");
}
int main() {
str posParam;
posParam = X;
printf("Enter a number:");
scanf("%s",&posParam);
if ( posParam == "X" ){
printf("Welcome to app!\nType: " + $0 + " t\nto show a message");
}else{
if (posParam == "t" ){
secretFunction();
}
return 0;
}
return 0;
I know this code is really crappy, I was trying to make an example of the above code in bash. I am not trying to convert a bash script into a C app, I'm trying to play around with it. I drew the idea of something I want to work on from the Wikipedia article on the MD5 checksum C app that takes a string and calculates the MD5 checksum for it. I cannot seem to work out what part they get the positional parameter to pass to the application.
This is a little different, I do understand, because it has prompted the user to provide an answer and then assign it to a value. I would rather use it as a positional parameter in the first instance.
What is $1 in Bash (et al) is argv[1] in a C program:
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc > 1)
{
printf("You provided at least one argument (or parameter)\n");
printf("The first argument is \"%s\"\n", argv[1]);
}
return 0;
}
The argument argc is the number of valid entries in the argv array. argv[0] is the executable name, and you can access up to argv[argc - 1]. (Actually you can access argv[argv] as well, it is always a NULL pointer).
As Joachim says, replace $0 with argv[0], also (assuming that str is a char*):
scanf("%s",&posParam);
^ there is no need to use &, posParam is already a pointer.
if ( posParam == "X" ){
strings can not be compared with ==, instead use:
if (strcmp(posParam, "X") == 0){
Related
So I am trying to make a linked list/binary tree and:
The user should be able to choose the data structure directly from the command line when it starts the program. This should use the argc or argv arguments to main()
how would I do this? I don’t get it why not just use switch case statement asking the student.
option 1: linked list
option 2: binary tree?
we didn’t really cover argc argv properly can anyone help?
Apparently its a duplicate ... hmm.. well i am asking specically about binary tree/linked list how would the user tell it to choose which data structure?
Experiment with the following skeleton program, and find out.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s COMMAND\n", argv[0]);
return EXIT_FAILURE;
}
if (!strcmp(argv[1], "foo")) {
printf("Doing foo.\n");
} else
if (!strcmp(argv[1], "bar")) {
printf("Doing bar.\n");
} else {
fprintf(stderr, "Unknown command line parameter '%s'.\n", argv[1]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The most common way to inform the utility user as to what to do, is to run the utility without parameters, or with -h or --help as the only parameter. (Windows command-line utilities might use /? or similar.)
Let's say the user can run the compiled program, program in the following ways:
./program list
./program tree
./program -h
./program --help
./program
where the first form tells the program to use a linked list; the second form tells the program to use a tree; and the other forms just output usage, information on how to call the program:
Usage: ./program [ -h | --help ]
./program MODE
Where MODE is one of:
list Linked-list mode
tree Tree mode
Further details on what the program actually does...
You achieve this with very little code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum {
NO_MODE = 0,
LIST_MODE,
TREE_MODE
};
int main(int argc, char *argv[])
{
int mode = NO_MODE;
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("Usage: %s [ -h | --help ]\n", argv[0]);
printf(" %s MODE\n", argv[0]);
printf("\n");
printf("Where MODE is one of\n");
printf(" list for linked list mode\n");
printf(" tree for tree mode\n");
printf("\n");
printf("Further details on what the program actually does...\n");
printf("\n");
return EXIT_SUCCESS;
}
if (!strcmp(argv[1], "list"))
mode = LIST_MODE;
else
if (!strcmp(argv[1], "tree"))
mode = TREE_MODE;
else {
fprintf(stderr, "%s: Unknown MODE.\n", argv[1]);
return EXIT_FAILURE;
}
/* mode == LIST_MODE or TREE_MODE here,
depending on the first command line parameter.
*/
return EXIT_SUCCESS;
}
Note that || operator is short-circuited in C: if the left side is false, the right side is not evaluated at all. So, above, the first strcmp() check is only done when argv == 2, and the second when argv == 2 and the first strcmp() returned nonzero (no match).
In other words, the body of the usage section is only run when argv != 2 (there is less than two, or more than two command line items, counting the program name as one); or if the sole command-line parameter matches either -h or --help.
! is the not operator in C. !x evaluates to 1 if and only if x is zero or NULL; and to 0 otherwise.
(You can confuse people by using !!x. It evaluates to zero if x is zero, and to one if x is not zero. Which is logical. It's often called the not-not operation.)
The enum is just there to remind you that magic constants are bad; it is better to use either enums, or preprocessor macros (#define NO_MODE 0 and so on). It would be terribly easy to use 1 in one place to indicate tree mode, and 2 in another; such bugs are horrible to debug, needs way too much concentration from the human reading the code, to find such bugs. So don't use magic constants, use enums or macros instead.
Above, I decided that NO_MODE has value zero, and let the compiler assign (increasing) values to LIST_MODE and TREE_MODE; consider them compile-time integer constants. (Meaning, you can use them in case labels in a switch statement.)
Because strcmp() returns zero if the two strings match, !strcmp(argv[1], "baz")) is true (nonzero) if and only if argv[1] contains string baz. You see it all the time in real-world code when strings are compared.
If you look at my answers here, you'll very often see an if (argc ...) "usage" block in my example code. This is because even I myself will forget, often within days, exactly what the purpose of the program is. I typically have several dozen example programs on my machines I've written, and rather than looking at the sources to see if something jogs my memory, I simply run the example snippets without command-line parameters (or actually, with -h parameter, since some are filters), to see what they do. It's faster, less reading, and I'll find the relevant snippet faster.
In summary, write an usage output block in all your programs, especially when it is just a test program you won't publish anywhere. They are useful, especially when you have a library full of them, of various code snippets (each in their own directory; I use a four-digit number and a short descriptive name) that implement interesting or useful things. It saves time and effort in the long run, and anything that lets me be efficient and lazy is good in my book.
argc = argument count, argv = array of arguments. argv[0] is the executing program. argv[1..n] are the arguments passed to the executable.
Example: I call the executable foo with 2 arguments, bar and bas:
foo bar bas
argc = 3, argv = [foo, bar, bas]
I am trying to understand how to use command line options with a command line c tool and I came accross this example.Can some one explain how the code flow works,I am not able to understand it,also I understand that it uses a getopt() function which is inbuilt.
The exe called is rocket_to and it has two command line options, e and a. e option takes 4 as an argument and a option takes Brasalia,Tokyo,London as argument.
Can some one explain how the code works?
This is the actual code:
command line:
rocket_to -e 4 -a Brasalia Tokyo London
code:
#include<unistd.h>
..
while((ch=getopt(argc,argv,"ae:"))!=EOF)
switch(ch){
..
case 'e':
engine_count=optarg;
..
}
argc -=optind;
argv +=optind;
There are many manual pages for getopt() including the POSIX specification. They describe what the getopt() function does. You can also read the POSIX Utility Conventions which describes how arguments are handled by most programs (but there are plenty of exceptions to the rules, usually because of historical, pre-POSIX precedent).
In the example outline code, the -e option takes an argument, and that is the 4 in the example command line. You can tell because of the e: in the third argument to getopt() (the colon following the letter indicates that the option takes an argument). The -a option takes no argument; you can tell because it is not followed by a colon in the third argument to getopt(). The names Brasilia, Tokyo, London are non-option arguments after the option processing is complete. They're the values in argv[0] .. argv[argc-1] after the two compound assignments outside the loop.
The use of EOF is incorrect; getopt() returns -1 when there are no more options for it to process. You don't have to include <stdio.h> to be able to use getopt().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int ch;
int aflag = 0;
char *engine_count = "0";
while ((ch = getopt(argc, argv, "ae:")) != -1)
{
switch (ch)
{
case 'a':
aflag = 1;
break;
case 'e':
engine_count = optarg;
break;
default:
fprintf(stderr, "Usage: %s [-a][-e engine] [name ...]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
argc -= optind;
argv += optind;
printf("A flag = %d\n", aflag);
printf("Engine = %s\n", engine_count);
for (int i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;
}
That is working code which, if compiled to create a program rocket_to, produces:
$ ./rocket_to -e 4 -a Brasilia Tokyo London
A flag = 1
Engine = 4
argv[0] = Brasilia
argv[1] = Tokyo
argv[2] = London
$ ./rocket_to -a -e 4 Brasilia Tokyo London
A flag = 1
Engine = 4
argv[0] = Brasilia
argv[1] = Tokyo
argv[2] = London
$ ./rocket_to -e -a 4 Brasilia Tokyo London
A flag = 0
Engine = -a
argv[0] = 4
argv[1] = Brasilia
argv[2] = Tokyo
argv[3] = London
$
From the getopt man page:
The getopt() function parses the command-line arguments. Its arguments argc and argv are the argument count and array as passed to
the main() function on program invocation. An element of argv that starts with '-' (and is not exactly "-" or "--") is an option element. The characters of this element (aside from the initial '-') are option characters. If getopt() is called repeatedly, it
returns successively each of the option characters from each of the option elements.
The 3rd argument to getopt() are the valid options. If the option is followed by a colon it requires an argument. The argument can be accessed through the optarg variable. So in your example you have two options: 'a' which takes no argument and 'e' which takes an argument.
If getopt() finds an options it returns the character. If all options are parsed it returns -1 and if an unknown option is found it returns -1.
So your code loops through all options and processes them in a switch statement.
Next time when you have trouble understanding something like this try to run man <unknown function> first.
I'm trying to write a program that accept file names as arguments in a bash script, then passes them to a C program that replaces spaces with underscores, then the bash script uses that to rename the file.
For example, the input would be
Bash bash_script "test test test.txt"
and the file would be renamed test_test_test.txt.
My problem is that when I run this, it tells me that I'm using mv incorrectly. Why is this? I'm new to bash, so I'm sorry for using program/script incorrectly.
My C program:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
char * file = argv[1];
while(i<=256){ //max file size is 256 characters on mac
if (argc != 2)
printf("Please provide one file name.");
else if(file[i] == ' ')
file[i] = '_';
i++;
}
printf("%s \n", file);
return 0;
}
My Bash program:
#! /bin/bash
VAR = "C_program '$#'"
mv $1 $VAR
This line:
VAR = "C_program '$#'"
doesn't do what you want. And your mv line is broken too.
VAR=$(C_program "$#")
mv "$1" "$VAR"
Also, your C program doesn't exit with an error when an error is detected.
Also, sed and tr are existing programs that are suitable alternatives to writing your C program to transliterate (translate) characters in strings.
Also, rename/prename are existing (Perl) programs that handle rename files with regular expression pattern functionality to rename files, which may be already available on your system(s).
In your specific example, I would not shell out to a custom C program to do this.
Here's an equivalent shell script (not requiring tr, sed or any programs besides bash and mv):
mv "$1" "${1// /_}"
In your specific problem, you are not setting your VAR properly. Shell scripts cannot accept spaces around the = when setting variables, and you need to use backticks or $() to execute an external program. So, properly written, you want
VAR="$(C_program "$#")"
If you just want the results than I would suggest simply replace the bash script and custom C program with a single short Bourne or POSIX shell script.
#!/bin/sh
NEW_FILE_NAME= `echo $1 | tr ' ' _ `
mv $1 $NEW_FILE_NAME
Otherwise
You want the shell script to run your C program (I'll refer to it as todash for simplicity) before setting the shell variable VAR. This is done using the backtick ` (located near upper right corner of US keyboards with tilde, '~') operation.
#!/bin/sh
VAR= `todash $1`
mv $1 $VAR
For todash.c I'll suggest a couple of mostly small improvements.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char *argv[])
{
char * filename;
/* Program operates on filename, not file or its contents, so use a variable
name that reflect that. Good variable names make debugging easier.
*/
if (argc != 2) {
printf("Please provide one file name.");
return EXIT_FAILURE; /* or exit(EXIT_FAILURE); */
} else {
/* Only set filename, once known that argv[1] is not NULL (empty) */
filename = argv[1];
}
/* Use a simple for loop
* PATH_MAX is a standard system constant included with limits.h
*/
for (i = 0; (i < PATH_MAX) && (filename[i] != '\0'); i++) {
if (filename[i] == ' ') {
filename[i] = '_';
}
}
printf("%s \n", filename);
return EXIT_SUCCESS;
}
The added length is only my additional inline comments.
The largest change was untangling the argc if comparison from the while loop, which once simplified, become a classic example of where to use a for loop.
And for your sanity, and those around you, use braces (curly brackets) around conditional blocks of code. Just because you are allowed to not include them, does not mean you should (not include them). Programs tend to live beyond their original intention and expand in the future. Avoid making mistakes later by including them now.
2 problems with the mv $1 "C_program '$#'"
$1 needs double quotes -> "$1"
"C_program '$#'" should be `C_program '$1'` or $(C_program '$#')
however this can be done more efficiently with
IFS="
"
for x in $#; do
mv "$x" "${x// /_}"
done
I'm making a program in C in linux environment. Now, program runs with arguments which I supply in the command line.
For example:
./programName -a 45 -b 64
I wanted to handle the case when my command line parameters are wrongly supplied. Say, only 'a' and 'b' are valid parameters and character other than that is wrong. I handled this case. But suppose if my command line parameter is like this:
./programName -a 45 -b
It gives segmentation fault(core dumped). I know why it gives because there is no arguments after b. But how can I handle this situation such that when this condition arrives, I can print an error message on screen and exit my program.
As per the main function wiki page:
The parameters argc, argument count, and argv, argument vector, respectively
So you can use your argc parameter to check whether or not you have the right number of arguments. If you don't have 4, handle it and proceed without segfault.
You can, and quite probably should, use getopt() or its GNU brethren getopt_long().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int b = 0;
int a = 0;
int opt;
while ((opt = getopt(argc, argv, "a:b:")) != -1)
{
switch (opt)
{
case 'a':
a = atoi(optarg);
break;
case 'b':
b = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: %s -a num -b num\n", argv[0]);
exit(1);
}
}
if (a == 0 || b == 0)
{
fprintf(stderr, "%s: you did not provide non-zero values for both -a and -b options\n", argv[0]);
exit(1);
}
printf("a = %d, b = %d, sum = %d\n", a, b, a + b);
return(0);
}
You can make the error detection more clever as you wish, not allowing repeats, spotting extra arguments, allowing zeros through, etc. But the key point is that getopt() will outlaw your problematic invocation.
We can't see what went wrong with your code because you didn't show it, but if you go accessing a non-existent argument (like argv[4] when you run ./programName -a 42 -b), then you get core dumps. There are those who write out option parsing code by hand; such code is more vulnerable to such problems than code using getopt() or an equivalent option parsing function.
I have this C program that gets the input from the user and sends it to a method:
#include <stdio.h>
#include <string.h>
#include "constants.h"
#include "lines.h"
#include "compare.h"
//gets arguments and sends to compare.c
int main() {
int op = 1;
char filename[20];
scanf("%d ", &op);
gets(filename);
if ((char) op + '0' < 49 || (char) op + '0' > 57) {
printf("Error: Invalid input");
exit(0);
}
readstdin(filename, op);
return 0;
}
but instead of executing the program and reading from stdin, I want it to read from the unix terminal so that:
./sort [field] < input_file
will read into the file. ([field] is option if no input is put in, default is 1).
For example the command to execute the C program in UNIX would look like this:
./sort 1 < test.txt
How do I go about doing this?
Any help is much appreicated
Thanks!
For a start, you're getting your arguments the wrong way in your code. If what you're wanting is to run your program such as ./sort <option> <filename>, then you don't use stdin to retrieve these arguments.
The arguments in a C program are passed to main using the following function signature:
int main(int argc, char *argv[])
argc is the number of command line arguments passed to the program, and argv is the array of strings of those arguments.
With a run of ./sort 5 test.in:
argc will equal 3
argv[0] will be "./sort"
argv[1] will be "5"
argv[2] will be "test.in"
You should check that the value of argc is 3 to ensure that 2 arguments have been passed ("5", "test.in"), as well as the filename ("./sort") for a total of 3.
If you want to have optional fields, it would be better to have them after the compulsory ones, or better yet is to use something like getopt where you could instead have something like: ./sort --file test.in or ./sort --opt 5 --file test.in. It's probably unnecessary for this case, but it's an option.
You can parse the integer option using atoi or strtol, however you like, to convert it from a string (char*) to an integral type and fopen, fgets, fclose to read from the input file.