由于Linux命令cd不能用作外部命令,是否可以编写我的cd版本(这不是shell-builtin命令)?

时间:2015-08-29 00:14:23

标签: linux shell operating-system

我对这个实现很好奇,可能是指一些低级细节,但我很乐意学习。

顺便说一句,我仍在寻找解决cd困境的解决方案而不重写该命令。如果你有任何简洁的解决方案,请随时在这里发布。

1 个答案:

答案 0 :(得分:1)

实际上,您无法编写自己的chdir外部命令。

更准确地说,你可以,但它对你没有帮助。问题是子进程中所做目录的更改对父进程的当前目录没有影响。当shell执行外部chdir命令时,chdir命令会更改其自己的当前目录,但调用它的shell将保持原样。

如果您真的想要做某事,可以考虑编写一个更改目录的chdir命令,然后在新目录中执行shell。如果您使用:

exec chdir /some/where

然后您的原始shell将替换为新的当前目录(/some/where)中的新shell。但这将是相当绝望的措施。请注意,如果您没有使用exec作为前缀,则每次更改目录时,都会获得一个新shell。它是一种目录堆栈,但您必须在出路时依次退出每个shell。如果您非常熟悉文件系统,那将会非常令人厌烦。

chdir.c

这是答案中概述的chdir命令的简单实现。

#include <stdlib.h>
#include <unistd.h>
#include "so-stderr.h"

static char def_shell[] = "/bin/sh";

int main(int argc, char **argv)
{
    char **cmdv;
    err_setarg0(argv[0]);

    if (argc <= 1)
        err_usage("directory [cmd [arg ...]]");
    if (chdir(argv[1]) != 0)
        err_syserr("failed to change directory to %s\n", argv[1]);

    if (argc == 2)
    {
        static char *args[3] = { 0, "-i", (char *)0 };
        char *shell = getenv("SHELL");
        if (shell == 0)
            shell = def_shell;
        args[0] = shell;
        cmdv = args;
    }
    else
        cmdv = &argv[2];

    execvp(cmdv[0], cmdv);
    err_syserr("failed to execute %s\n", cmdv[0]);
    /*NOTREACHED*/
    return 0;
}

报告错误

唯一稍微复杂的部分是使用so-stderr.hso-stderr.c中的错误报告功能,因为它们不是标准功能。它们只是我编写的函数,我用于基本上所有程序中的错误报告。

带有so-前缀的文件名是包含标题stderr.h和源stderr.c的更复杂代码块的最小版本(没有注释的40多行)(加上一些辅助文件,大约1000行注释,在更多功能中提供更复杂的接口,一般更多控制)。这是chdir程序使用的大大简化(但功能齐全)的函数形式。

so-stderr.c

#include "so-stderr.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char *argv0 = "**undefined**";

void err_setarg0(const char *arg0)
{
    argv0 = arg0;
}

void err_usage(const char *usestr)
{
    fprintf(stderr, "Usage: %s %s\n", argv0, usestr);
    exit(EXIT_FAILURE);
}

void err_syserr(const char *fmt, ...)
{
    int errnum = errno;
    fprintf(stderr, "%s: ", argv0);
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, "(%d: %s)", errnum, strerror(errnum));
    putc('\n', stderr);
    exit(EXIT_FAILURE);
}

如果我想依赖C11,三个函数中的两个将被标记为noreturn。这是主stderr包中支持的另一个额外细节。

所以-stderr.h

#ifndef SO_STDERR_H_INCLUDED
#define SO_STDERR_H_INCLUDED

extern void err_setarg0(const char *arg0);
extern void err_syserr(const char *fmt, ...);
extern void err_usage(const char *usestr);

#endif /* SO_STDERR_H_INCLUDED */