Passing arguments through bash script to C program - c

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

Related

Fill argv[1] in C with max input

I am trying figure out a simple way to fill argv[1] with an extremely large string of input to see how much input my program can handle. Any ideas on the simplest way to do this?
If you're using a POSIX shell (Like Bash on Linux or similar) then you could use a simply Python script to "fill" an argument, and call it using the shell back-tick to execute commands "inline":
./your_program `python -c "print('A'*100)"`
The above will create a string of 100 A characters as the first argument to the program.
If you are calling your program from a shell, you typically take the advantage of that.
For instance, for POSIX, something like:
./program `printf '%*s' 500 | tr ' ' x`
(Taken from Creating string of repeated characters in shell script)
You can also create the string dynamically over a loop to test the program until it crashes, etc.
If you want a C solution (without spawning another process, e.g. using something like system or OS-specific APIs), I would suggest you rename your main() into a different function, and then write a new main() that calls the old one with an argv customized however you like:
int old_main(int argc, char *argv[]) { ... }
int main()
{
int argc = 2;
char *argv[2] = {
"program",
"xxxxxxxxxxxxxxxxxxxxxxx",
};
return old_main(argc, argv);
}

How to take the output of grep and write it to a new file

I want to take the output of the grep command on a file, create a new file and save that grep output to the new created file, can someone please point me to the right direction in how I would do that?
The path you choose depends a great deal on how simple you want it to be.
Perhaps the simplest method is the use of system:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
system ("grep a *.c >outfile.txt");
return 0;
}
though you also could construct the command dynamically if you have different arguments to grep or a non-fixed output file.
Beyond that, you could use popen() (if available on your implementation - it's not mandated by ISO but is instead a POSIX thing) along with fgets() or fgetc() to read the output of that command and do whatever you want with it:
#include <stdio.h>
int main (void) {
int chr;
FILE *echo = popen ("echo hello there", "r");
if (echo != NULL) {
while ((chr = fgetc (echo)) != EOF)
putchar (chr);
fclose (echo);
}
return 0;
}
The next step up from there may be to not rely on an external grep at all but instead include something like PCRE (Perl-compatible regular expressions) into your own code, giving you much finer control over what happens.

Example app in C that takes 2 positional parameters

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){

C-Linux-How to send C parameter value to awk script?

I'm quite new to Linux and not familiar with C. Here I have one question about both.
I'm writing a C program to run in Linux. And I have a file names f.txt in the same folder. With some fields like this:
Jason 12 Male
I want to compare the $2 of the txt file of each line with the value of parameter a. If the second field of the line is greater than a, then print the first field $1.
I tried codes like this but not work. Can anybody help? Thanks!
void main()
{ int a;
scanf("%d",&a);
char* comm="awk '{if($2>"+a+") print $1}' f.txt";
system(comm);
}
For your stated problem, which is just basic text file processing, it is probably easiest to solve this task using a scripting language itself, rather than using C (such as python, perl, or awk itself).
For your programming problem, the C language does not support that kind of string concatenation. You have to build the string using a call to snprintf() (or via calls to strcat()).
char comm[512];
int r = snprintf(comm, sizeof(comm), "awk '{if($2>%d) print $1}' f.txt", a);
if (r < 0) {
/* error */
} else if (r < sizeof(comm)) {
/* ok */
} else {
/* need a bigger comm buffer... */
}
An alternative approach to handling this problem would be the following: Read the bytes from stdin with the following snippet:
while ( ( char *data = scanf( "%s %d %s\n" ) ) != EOF )
... where the newline is your delimiter. Then you can perform the appropriate actions on "data" to access each field individually.
It would be ran by piping your text file to the program:
./program < textfile.txt

How to pass shell variable as a command line arguments in C program

I want to pass shell variable as command line arguments to C program. To practice this I have written a basic C program which is as follows:
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char **argv){
int i, a, prod=1 ;
if(argc==2)
a = atoi(argv[1]);
else
a = 8 ;
printf("value of cmd: %d\n",a);
for(i=1; i <= a ; i++)
prod *= i ;
printf("factorial %d!= %d\n",a, prod);
}
Now to pass the argument through shell script variable, I have written a small script which is as follows:
#!/bin/bash
echo "Welcome to the small shell scripting!!!"
for ((i=4; i<9;i++))
do
"../programming/ctest/arg $i"
done
Where ../programming/ctest/arg is the executable file for the above C program. But when I run the script output is ../programming/ctest/arg 4 no such file or directory and so on. while running without shell variable It gives the proper output.
Kindly look at that, if this issue is solved I will use it for further automation
"../programming/ctest/arg $i"
You need to remove quotes good sir
../programming/ctest/arg $i
To elaborate, without removing the quotes Bash will interpret the entire string as a command, instead of a command and argument like you intended.

Resources