【问题标题】:How to code my own version of mv (rename/move) unix command in C language?如何用 C 语言编写我自己版本的 mv(重命名/移动)unix 命令?
【发布时间】:2016-07-17 22:01:16
【问题描述】:

我想为 move(mv) Unix 命令编写自己的代码。我对 C 语言完全陌生,显然不知道如何修复我的代码。如果两个输入都是文件名,我想执行重命名文件等操作。如果 dest_folder 是一个目录,我想将文件移动到该目录中。

但我无法修复特定问题的代码,因为我不太熟悉目录,尤其是 C。该程序需要 2 个输入源和目标,然后执行必要的功能。我显然可以重命名我的文件,但由于某种我不知道的原因,我无法将文件移动到特定文件夹?

在将文件移动到特定目录时需要帮助。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define SBUF 256
#define DBUF 256

    int main(int ac, char *argv[])
    {
      DIR* dir_ptr;     // the directory
      struct dirent* direntp;


      if( ac == 1 )
      {
        printf("Usage:  %s MOVE\n", argv[0] );
        exit(0);
      }


      if(ac>1 && ac<3)
      {
        printf("Error! few arguments provided " );
        exit(0);
      }

        char src_folder[SBUF];
        char dest_folder[DBUF];
        strcpy(src_folder, argv[1]);
        strcpy(dest_folder, argv[2]);


        dir_ptr = opendir("."); //open directory
        if ( dir_ptr == NULL )
        {
            perror( "." );
            exit( 1 );
        }

        while( (direntp = readdir( dir_ptr )) != NULL ) 
        {
            if (  strcmp(direntp->d_name, dest_folder) !=0) //search file or directory
            {
                printf("found the file %s", dest_folder);

                break;
            }else
                printf("not found");
                break;
        }
        rename(src_folder, dest_folder);
        closedir( dir_ptr );

        return 0;
    }

【问题讨论】:

  • 我认为不需要opendir/readdir/closedirrename 将为您检查文件是否存在。
  • 您可能需要检查权限,以防它们在您的测试中发挥作用。您是否看到错误消息?你能指出你的代码中到底有什么不工作的地方吗?
  • @Elyasin 在我的终端上运行代码时,我没有收到任何错误消息。另外我不确定要指出什么,因为没有错误,但可能有一部分代码丢失并且不允许我移动或重命名文件,这是我无法弄清楚的?
  • @Elyasin 显然我想出了如何重命名在我的代码中工作正确的方法,但我仍然无法将文件移动到我不知道为什么的特定文件夹?我也更改了权限!
  • 移动/重命名文件时,您只需要四件事:文件名、文件新名称、文件目录、文件新目录。我相信有了这四个,您可以轻松“移动”您的文件。那么权限是次要的

标签: c linux unix


【解决方案1】:

rename(3) 无法按照您希望的方式工作(我不知道为什么,请咨询委员会)。正如手册页所说,您不能使用rename(some_file, some_directory)

只需使用stat(2)(或lstat(2),如有必要)并检查您收到的内容。这是一个简短的可运行草图。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

    // check if it is the same inode on the same device
#define SAME_INODE(a, b) ((a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)

    // ALL CHECKS OMMITTED!

int main(int argc, char **argv)
{

  struct stat statbuf_src, statbuf_dest;
  char *src, *dest, *new_src, *new_dest;
  char *current_directory;

  if (argc != 3) {
    fprintf(stderr, "usage: %s src dest\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  // work on copy
  src = malloc(strlen(argv[1]) + 1);
  dest = malloc(strlen(argv[2]) + 1);
  strcpy(src, argv[1]);
  strcpy(dest, argv[2]);

  stat(src, &statbuf_src);
  stat(dest, &statbuf_dest);

  // there are many more, of course
  printf("\"%s\" is a ", src);
  if (S_ISREG(statbuf_src.st_mode)) {
    puts("a regular file");
  }
  if (S_ISDIR(statbuf_src.st_mode)) {
    puts("a directory");
  }

  printf("\"%s\" is a ", dest);
  if (S_ISREG(statbuf_dest.st_mode)) {
    puts("a regular file");
  }
  if (S_ISDIR(statbuf_dest.st_mode)) {
    puts("a directory");
  }

  if (SAME_INODE(statbuf_dest, statbuf_src)) {
    printf("%s and %s are the identical\n", src, dest);
  }
  // if that is not set you have to do it by hand:
  // climb up the tree, concatenating names until the inodes are the same
  current_directory = getenv("PWD");
  printf("current directory is \"%s\"\n", current_directory);

  // I'm pretty sure it can be done in a much more elegant way
  new_src = malloc(strlen(src) + 1 + strlen(current_directory) + 1);
  strcpy(new_src,current_directory);
  strcat(new_src,"/");
  strcat(new_src,src);
  printf("new_src = %s\n",new_src);

  new_dest = malloc(strlen(dest) + 1 + strlen(current_directory) + 1 + strlen(src) + 1);
  strcpy(new_dest,current_directory);
  strcat(new_dest,"/");
  strcat(new_dest,dest);
  strcat(new_dest,"/");
  strcat(new_dest,src);
  printf("new_dest = %s\n",new_dest);

  if(rename(new_src,new_dest) != 0){
    fprintf(stderr,"rename failed with error %s\n",strerror(errno));
  }

  free(new_src);
  free(new_dest);
  free(src);
  free(dest);

  exit(EXIT_SUCCESS);
}

编辑:为下面的描述添加代码 最后你有一个你所在的路径,如果给定的参数是目录或常规文件和路径的信息。如果源是常规文件而目标是目录,则将路径与常规文件的名称、目录名称的路径和常规文件的名称(您的源)连接起来

没有

Path = /home/foo
src = bar
dest = coffee

构建

new_src = /home/foo/bar
new_dest = /home/foo/coffee/bar

这样对rename()的调用是

rename(new_src, new_dest);

这样您就可以将常规文件重命名为rename() 接受的常规文件。

请注意rename() 并不适用于每个文件系统,但大多数情况下。

【讨论】:

  • 我按照您告诉我的流程进行了操作。我确实将路径与常规 src 文件连接起来,以便将 scr 文件移动到目录中,同样我也做了./move hello1.txt check 之类的参数,但它没有将文件移动到目录中。我不知道为什么我在连接后做了rename(src_folder, dest_folder);。我可能做错了什么,请提及谢谢。
  • src = malloc(strlen(argv[1])); ... strcpy(src,argv[1]); 肯定是内存分配不足。
  • @chux 哎呀!不应该发生,即使是草图也不应该发生。多么尴尬!谢谢!
  • @bmath 将代码完成到以下状态:“为我工作”。
  • 这不完整。如果目标路径在不同的文件系统上,mv 最终会复制该文件,本质上是在做 cp 所做的事情。
【解决方案2】:

如您所知,mv 是通过重命名实现的。 rename 是一个原子系统调用,可以将文件重命名为 file ,将 emtpy 目录重命名为空目录或将目录重命名为目录(dest 必须是非实体)。所以有以下情况需要处理:

  1. mv file1 file2 - 使用重命名功能

  2. mv dir1 dir2(nonentity or empty) - 使用重命名函数

  3. mv dir1 dir2(not empty) - 将 dir1 重命名为 dir2/dir1

  4. mv 文件 dir(exist) - 将文件重命名为 dir/file

  5. mv dir 文件 - 非法操作

你能理解吗?

【讨论】:

    猜你喜欢
    • 2012-12-07
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    • 2017-12-12
    • 2015-12-08
    • 1970-01-01
    相关资源
    最近更新 更多