User1996
User1996

Reputation: 393

Passing arguments through bash script to C program

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

Upvotes: 0

Views: 4966

Answers (4)

technosaurus
technosaurus

Reputation: 7812

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

Upvotes: 0

mctylr
mctylr

Reputation: 5169

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.

Upvotes: 0

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 799520

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

Upvotes: 1

nneonneo
nneonneo

Reputation: 179717

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 "$@")"

Upvotes: 0

Related Questions