Reputation: 393
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
Reputation: 7812
2 problems with the mv $1 "C_program '$@'"
however this can be done more efficiently with
IFS="
"
for x in $@; do
mv "$x" "${x// /_}"
done
Upvotes: 0
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
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
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