Relation between PATH env and argv[0] - c

Generally argv[0] is as same as exec file name. For example:
If I execute program with ./my_program then argv[0] is ./my_program
If I execute program with /home/username/my_program then argv[0] is /home/username/my_program.
My question is, if PATH=/home/username why I can't see argv[0] value?
This is my real situation
PATH=/home/knight/bin:/home/knight/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/knight
My test program source is:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%s\n", argv[0]);
}
My home directory is /home/knight so I can execute program directly.
knight#knight-desktop:~$ test
knight#knight-desktop:~$ ./test
./test
I can't understand, why doesn't the knight#knight-desktop:~$ test command print any result?

Because test is a shell builtin command.
And there is a big difference between ./test(it is an executable file) while test is a command passed direct to the shell of which if typed incorrect, it could have been not recognised for example lets say you use the command tst the result will be -bash: tst: command not found
To check if any word is a builtin command/reserved keyword for shell,use command type.
on terminal,
$type test
test is a shell builtin
$type if
if is a shell keyword

Related

Running two commands using C and Linux environment variables

I'm trying to run two commands using a C program and a Linux environment variable:
#Program name is execute
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char cmd[256] = "/home/username/hello.sh $USER";
execl("/bin/bash", "bash", "-p", "-c", cmd, NULL);
return 0;
}
However, when running the program with the $USER environment variable set to a second command, the second command will not run.
env USER=";cat /home/username/hello.txt" ./execute
Hello from shell script
Hard coding the second command into the C program works:
char cmd[256] = "/home/username/hello.sh ;cat /home/username/hello.txt";
./execute
Hello from shell script
Hello from text file
I want my C program to return:
env USER=";cat /home/username/hello.txt" ./execute
Hello from shell script
Hello from text file
How can I get it to work, without changing the C program?
The only processing that's done on the result of expanding variables is word splitting and globbing. It doesn't process characters like ; to separate commands, > for output redirection, $ for further variable expansions, etc.
If you want to force a full parse of the command, you have to use eval.
char cmd[256] = "eval /home/username/hello.sh $USER";
execl("/bin/bash", "bash", "-p", "-c", cmd, (char*)NULL);

Provide input parameters to C code from Linux shell

The concept of my code is like:
#include <stdio.h>
int main(int argc, char *argv[])
{
int num;
FILE *fp;
getint("num",&num); /* This line is pseudo-code. The first argument is key for argument, the second is the variable storing the input value */
fp = inputfile("input"); /* This line is pseudo-code. The argument is key for argument, fp stores the return file pointer */
...
...
exit(0);
}
Usually, after compiling the code and generating the executable main, in the command line we write this to run the code:
./main num=1 input="data.bin"
However, if there's too many arguments, type in the command line each time we run the code is not convenient. So I'm thinking about writing the arguments and run in Linux shell. At first I wrote this:
#! /bin/sh
num = 1
input="data.bin"
./main $(num) $(input)
But error returns:
bash: adj: command not found
bash: input: command not found
bash: adj: command not found
bash: input: command not found
Can anybody help to see and fix it.
There are three main problems with your code:
You can't use spaces around the = when assigning values
You have to use ${var} and not $(var) when expanding values.
The way your code is written, you are passing the string 1 instead of your required string num=1 as the parameter.
Use an array instead:
#!/bin/bash
parameters=(
num=1
input="data.bin"
)
./main "${parameters[#]}"
num=1 is here just an array element string with an equals sign in it, and is not related to shell variable assignments.

run linux command using execlp with more than one argument as string in c

I am trying to run ls using system calls in C with more than one argument, for example -l -a. The arguments and their number is changing depending on the user input. The input is concatenated "-l" + "-a" == "-l -a". The code I'm using is:
execlp("ls","ls",arguments,NULL) //arguments = "-l -a"
The user input is from Terminal:
-l
-a
if you want to executes more than one argument , then you should use execvp() instead of execlp.
#include<stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
execvp(argv[1],argv+1);// argv+1 means whatever arguments after argv[1] it will take & executes it
return 0;
}
for e.g your input like that
xyz#xyz-PC:~$ ./a.out ps -el
I hope it helps.

Calling execve bash on bash scripts can't find arguments

I have two (Ubuntu Linux) bash scripts which take input arguments. They need to be run simultaneously. I tried execve with arguments e.g.
char *argv[10] = { "/mnt/hgfs/F/working/script.sh", "file1", "file2", NULL };
execve(argv[0], argv, NULL)
but the bash script can't seem to find any arguments at e.g. $0, $1, $2.
printf "gcc -c ./%s.c -o ./%s.o\n" $1 $1;
gcc -c ./$1.c -o ./$1.o -g
exit 0;
output is gcc -c ./main.c -o ./main.o
and then a lot of errors like /usr/include/libio.h:53:21: error: stdarg.h: No such file or directory
What's missing?
Does your script start with the hashbang line? I think that's a must, something like:
#!/bin/bash
For example, see the following C program:
#include <stdio.h>
#include <unistd.h>
char *argv[10] = { "./qq.sh", "file1", NULL };
int main (void) {
int rc = execve (argv[0], argv, NULL);
printf ("rc = %d\n", rc);
return 0;
}
When this is compiled and run with the following qq.sh file, it outputs rc = -1:
echo $1
when you change the file to:
#!/bin/bash
echo $1
it outputs:
file1
as expected.
The other thing you need to watch out for is with using these VMWare shared folders, evidenced by /mnt/hgfs. If the file was created with a Windows-type editor, it may have the "DOS" line endings of carriage-return/line-feed - that may well be causing problems with the execution of the scripts.
You can check for this by running:
od -xcb /mnt/hgfs/F/working/script.sh
and seeing if any \r characters appear.
For example, if I use the shell script with the hashbang line in it (but appen a carriage return to the line), I also get the rc = -1 output, meaning it couldn't find the shell.
And, now, based on your edits, your script has no trouble interpreting the arguments at all. The fact that it outputs:
gcc -c ./main.c -o ./main.o
is proof positive of this since it's seeing $1 as main.
The problem you actually have is that the compiler is working but it cannot find strdarg.h included from your libio.h file - this has nothing to do with whether bash can see those arguments.
My suggestion is to try and compile it manually with that command and see if you get the same errors. If so, it's a problem with what you're trying to compile rather than a bash or exec issue.
If it does compile okay, it may be because of the destruction of the environment variables in your execve call.

Handling command line flags in C/C++

I am looking for a very simple explanation/tutorial on what flags are. I understand that flags work indicate a command what to do. For example:
rm -Rf test
I know that the rm command will remove the test folder and that the -Rf flags will force the command to erase not just the folder but the files in it.
But, where are the flags read/compiled??? What handles the flags? Can I, for example, write my own C/C++ program and designate different flags so that the program does different things? I hope I am asking the right questions. If not, please let me know.
At the C level, command line arguments to a program appear in the parameters to the main function. For instance, if you compile this program:
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;
}
and invoke it with the same arguments as your example 'rm' command, you get this:
$ ./a.out -Rf test
argv[0] = ./a.out
argv[1] = -Rf
argv[2] = test
As you can see, the first entry in argv is the name of the program itself, and the rest of the array entries are the command line arguments.
The operating system does not care at all what the arguments are; it is up to your program to interpret them. However, there are conventions for how they work, of which the following are the most important:
Arguments are divided into options and non-options. Options start with a dash, non-options don't.
Options, as the name implies, are supposed to be optional. If your program requires some command-line arguments to do anything at all useful, those arguments should be non-options (i.e. they should not start with a dash).
Options can be further divided into short options, which are a single dash followed by a single letter (-r, -f), and long options, which are two dashes followed by one or more dash-separated words (--recursive, --frobnicate-the-gourds). Short options can be glommed together into one argument (-rf) as long as none of them takes arguments (see below).
Options may themselves take arguments.
The argument to a short option -x is either the remainder of the argv entry, or if there is no further text in that entry, the very next argv entry whether or not it starts with a dash.
The argument to a long option is set off with an equals sign: --output=outputfile.txt.
If at all possible, the relative ordering of distinct options (with their arguments) should have no observable effect.
The special option -- means "do not treat anything after this point on the command line as an option, even if it looks like one." This is so, for instance, you can remove a file named '-f' by typing rm -- -f.
The special option - means "read standard input".
There are a number of short option letters reserved by convention: the most important are
-v = be verbose
-q = be quiet
-h = print some help text
-o file = output to file
-f = force (don't prompt for confirmation of dangerous actions, just do them)
There are a bunch of libraries for helping you parse command line arguments. The most portable, but also the most limited, of these is getopt, which is built into the C library on most systems nowadays. I recommend you read all of the documentation for GNU argp even if you don't want to use that particular one, because it'll further educate you in the conventions.
It's also worth mentioning that wildcard expansion (rm -rf *) is done before your program is ever invoked. If you ran the above sample program as ./a.out * in a directory containing only the binary and its source code you would get
argv[0] = ./a.out
argv[1] = a.out
argv[2] = test.c
This simple program should demonstrate the arguments passed to the program (including the program name itself.)
Parsing, interpreting and using those arguments is up to the programmer (you), although there are libraries available to help:
int main(int argc, char* argv[])
{
int i;
for(i=0; i<argc; ++i)
{ printf("Argument %d : %s\n", i, argv[i]);
}
return 0;
}
If you compile this program into a.out, and run it as:
prompt$> ./a.out ParamOne ParamTwo -rf x.c
You should see output:
Argument 0 : a.out
Argument 1 : ParamOne
Argument 2 : ParamTwo
Argument 3 : -rf
Argument 4 : x.c
Actually you can write your own C++ programm which accepts commandline parameters like this:
int main(int argc, char* argv[]){}
The variable argc will contain the number of parameters, while the char* will contain the parameters itself.
You can dispatch the parameters like this:
for (int i = 1; i < argc; i++)
{
if (i + 1 != argc)
{
if (strcmp(argv[i], "-filename") == 0) // This is your parameter name
{
char* filename = argv[i + 1]; // The next value in the array is your value
i++; // Move to the next flag
}
}
}
In your own C program you can process command line options in any way you see fit.
Command line parameters in C come in the parameters of the main(int argc, char *argv[]) method as strings.
And if you'd like to process command line parameters in a way similar to most UNIX commands, the function you're probably looking for is getopt()
Good luck!
The easiest thing is to write your main() like so:
int main(int argc, char* argv[]) { ...
Then inside that main you decide what happens to the command line arguments or "flags". You find them in argv and their number is argc.
flags are arguments passed into the main entry point of the program. For example, in a C++ program you can have
int main(int arc, char* argv[]){
return 0;
}
your arc is the # of arguments passed in, and the pointer gives u the list of actual arguments. so for
rm -Rf test
argc would be 3, and the argv array would contain your arguments. Notice argc >= 1 because the program name itself counts (rm). -RF is your 2nd parameter and test is your third.
So whenever you are typing commands in unix, you essentially are executing programs and passing them parameters that they operate on.
If you are really REALLY interested in the unix OS, you should look up forks and how they work. This can get pretty confusing to a newcomer though, so only if you are really interested in OS and how programs are executed.
GNU libc, which is very likely available on your system, has a library for this called getopt that can be used to parse the options in a sensible fashion. There are examples to get you started in the documentation linked below.
http://www.gnu.org/software/libc/manual/html_node/Getopt.html#Getopt

Resources