为什么在使用 cd 和 rm 命令循环调用时 system() 不起作用?

为什么在使用 cd 和 rm 命令循环调用时 system() 不起作用?

我最近开始使用 Linux,所以我的程序仅供学习。话虽如此,这是我的代码:

#include <stdio.h>
#include <stdlib.h>

int main () {

FILE *fin;
char buf[200];

fin = fopen("provaMake.txt", "r");
if (fin==NULL) {
    fin = fopen("/home/giorgio/Desktop/provaMake.txt", "r");
    if (fin==NULL) {
        printf("finError\n");
        exit(1);
    }
}

while(fgets(buf, 200, fin) != NULL) {

    system(buf);

}

fclose(fin);

}

这是provaMake.txt文件:

cd /home/giorgio/Desktop/a
rm -f pippo.txt
cd /home/giorgio/Desktop

当我使用以下命令运行它时:

$gcc provaMake.c -o provaMake.o
$./provaMake.o

它没有删除 pippo.txt (位于a目录内部Desktop)。

我在代码中做错了什么吗?我再说一遍,我正在努力学习,所以请向我解释一下(或者告诉我在哪里可以学习)。

答案1

system()在 shell 中运行命令。该 shell 是一个新的过程。它是你的 C 程序的一个子进程。cd命令更改运行它的 shell 进程的当前目录。该 shell 的子进程将继承该目录。但它不会影响父进程的当前目录。

您调用了system()三次。每次都会启动一个 shell 进程,运行一个命令,然后结束。cd一次调用system()不会影响单独调用的当前目录system()

如果你必须使用system(),那么解决问题的最佳方法可能是避免使用cd,而只需用一个命令完成所有操作。但这只有在你可以更改 时才有效provaMake.txt。具体来说,这应该像 的内容一样工作provaMake.txt

rm -f /home/giorgio/Desktop/a/pippo.txt

如果你必须使用system()但不能或不想更改provaMake.txt,或者你特别感兴趣如何使用system()运行文件中的所有命令在同一个 shell 进程中,那么您可以传递system()一个硬编码命令,该命令启动一个新 shell 并在同一 shell 中运行该文件中的所有命令。例如,您的 C 程序可以使用以下代码:

system(". /home/giorgio/Desktop/provaMake.txt");

您可以使用该命令替换整个程序。不需要缓冲区,因为您的 C 程序本身并不从文件中读取。同样,也不fopen()需要调用。shell 负责打开、读取文件并执行文件中的命令 - 这是其.内置操作,使用任何 Bourne 风格的 shell 时都会出现。(system()使用sh,它是 Bourne 风格的 shell,原样bash)。

请注意,如果您的 C 程序随后依赖或以其他方式观察其当前工作目录,那么它仍然不会受到cd运行的命令的影响(就像在您的原始代码中一样),因为它们仅在 shell 中运行。


有时,出于学习目的,以人为的方式做事是合理的,所以我不想告诉你不要编写一个 C 程序来system()逐个运行文件中所有的 shell 命令。但是,如果你的实际目标只是运行文件中的所有命令,那么你不需要 C 程序。你可以直接使用你的 shell:

  • 如果你想在你的当前的shell 进程,以便它的环境受到影响 - 例如,以便cd命令的效果之后仍然存在 - 那么您只需运行:

    . /home/giorgio/Desktop/provaMake.txt
    
  • 如果你想在新的shell,这样当前shell的环境就不会受到影响,然后将文件的名称作为命令行传递给shell:

    bash /home/giorgio/Desktop/provaMake.txt
    

    如果您正在使用的或想要使用的 shell 不是 bash,则可以调整该命令。例如:

    sh /home/giorgio/Desktop/provaMake.txt
    
  • 您可能希望使命令列表本身可执行。为此,请在开头添加类似以下内容(根据应使用哪个 shell 来解释它进行调整):

    #!/bin/bash
    

    并通过运行以下命令更改其权限以使其可执行:

    chmod +x filename

    代替filename替换为实际的文件名,例如/home/giorgio/Desktop/provaMake.txt

    然后您可以像运行任何程序一样运行该文件:

    ./provaMake.txt  # when you're in the directory that contains it
    
    /home/giorgio/Desktop/provaMake.txt  # from anywhere
    

尤其是在最后一种情况下,用后缀命名文件是不常见的.txt。通常,内容将通过.内置命令运行的文件通常用后缀命名.sh,而将被标记为可执行文件并作为脚本运行的文件则不带后缀。(不过,就 shell 和操作系统而言,文件名并不重要。)

答案2

我不知道为什么它对你不起作用,当我尝试类似的东西时它起作用了。

无论如何,添加一些printf语句对于理解程序正在做什么非常有帮助。例如,尝试在 while 循环中调用之前添加此行system

printf("Now calling system() with buf = %s\n", buf);

然后再次编译并运行并查看输出,希望这能帮助您了解发生了什么。

相关内容