通过bash脚本将参数传递给C程序

时间:2014-08-11 20:14:18

标签: c bash command-line-arguments

我正在尝试编写一个程序,在bash脚本中接受文件名作为参数,然后将它们传递给用下划线替换空格的C程序,然后bash脚本使用它来重命名文件。

例如,输入将是

Bash bash_script "test test test.txt"

,文件将重命名为test_test_test.txt

我的问题是,当我运行它时,它告诉我我错误地使用mv。为什么是这样?我是bash的新手,所以我很抱歉错误地使用了程序/脚本。

我的C程序:

#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;
}

我的Bash计划:

#! /bin/bash

VAR = "C_program '$@'"
mv $1 $VAR

5 个答案:

答案 0 :(得分:1)

这一行:

VAR = "C_program '$@'"

没有做你想要的。你的mv行也被破坏了。

VAR=$(C_program "$@")
mv "$1" "$VAR"

此外,当检测到错误时,您的C程序不会退出并显示错误。

此外,sedtr是现有的程序,它们是编写C程序以在字符串中音译(翻译)字符的合适替代方法。

此外,rename / prename是现有(Perl)程序,它们处理具有正则表达式模式功能的重命名文件,以重命名文件,这些文件可能已在您的系统上可用。

答案 1 :(得分:0)

在您的具体示例中,我不打算使用自定义C程序来执行此操作。

这是一个等效的shell脚本(不需要trsedbashmv以外的任何程序):

mv "$1" "${1// /_}"

在您的具体问题中,您没有正确设置VAR。设置变量时,Shell脚本无法接受=周围的空格,您需要使用反引号或$()来执行外部程序。所以,写得好,你想要

VAR="$(C_program "$@")"

答案 2 :(得分:0)

mv $ 1&#34; C_program&#39; $ @&#39;&#34;

的2个问题
  • $ 1需要双引号 - &gt; &#34; $ 1和#34;
  • &#34; C_program&#39; $ @&#39;&#34;应该是`C_program&#39; $ 1&#39;`或$(C_program&#39; $ @&#39;)

然而,这可以通过

更有效地完成
IFS="
"
for x in $@; do
    mv "$x" "${x// /_}"
done

答案 3 :(得分:0)

如果您只想要比我建议的结果,只需用一个简短的Bourne或POSIX shell脚本替换bash脚本和自定义C程序。

#!/bin/sh
NEW_FILE_NAME= `echo $1 | tr ' ' _  `
mv $1 $NEW_FILE_NAME

否则

在设置shell变量todash之前,您希望shell脚本运行您的C程序(为简单起见,我将其称为VAR)。这是使用反引号`(位于美国键盘右上角,使用波浪号,'〜')操作完成的。

#!/bin/sh
VAR= `todash $1`
mv $1 $VAR

对于todash.c我会建议几个小改进。

#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;
}

增加的长度只是我的额外内联评论。

最大的变化是解除argc if循环的while for比较,这个简化曾经简化过,成为使用{{1}}循环的典型示例。< / p>

为了您的理智以及周围的人,请在条件代码块周围使用大括号(大括号)。仅仅因为你被允许不包括它们,并不意味着你应该(不包括它们)。计划往往超出其初衷,并在未来扩展。现在可以通过包含它们来避免犯错。

答案 4 :(得分:0)

我大部分是第二个mctylr,但推荐一个更干净的循环版本:

for ( ; *file != '\0'; file++ ) {
    if ( *file == ' ' ) *file = '_';
}

这就是数组指针的强大功能。现在你节省了大约4个字节并且有一些漂亮的代码可以启动。

这远非仅仅是改款。您的代码实际上非常危险,因为如果&#39; argv [1]&#39; 小于256个字符,您正在读取超出数组边界的任意内存并可能写入(在假设的情况下,filepath的长度为0,接下来的255个空格在内存中将被改为下划线。)

相反,检查这是否等于true:

if ( strlen ( argv[1] ) > 256 )

...如果有,则退出并出现错误。 然后阅读argv [1]。

如果我有任何不妥,请纠正我,我绝不是专家。