Pergunta

Estou escrevendo meu próprio shell em C.Ele precisa ser capaz de exibir o diretório atual do usuário, executar comandos com base no caminho completo (deve usar execv) e permitir que o usuário altere o diretório com cd.

Este é o dever de casa.O professor nos deu apenas uma introdução básica em C e um breve resumo de como o programa deveria funcionar.Como não sou de desistir facilmente, estou pesquisando como fazer isso há três dias, mas agora estou perplexo.

Isto é o que tenho até agora:

  • Exibe o nome de usuário, o nome do computador e o diretório atual do usuário (o padrão é o diretório inicial).
  • Solicita entrada do usuário e obtém a entrada
  • Divide a entrada do usuário por " " em uma matriz de argumentos
  • Divide a variável de ambiente PATH por ":" em uma matriz de tokens

Não tenho certeza de como proceder a partir daqui.Eu sei que preciso usar o comando execv, mas em minha pesquisa no Google não encontrei um exemplo que eu entenda.Por exemplo, se o comando for bin/ls, como o execv sabe a exibição de todos os arquivos/pastas do diretório inicial?Como posso informar ao sistema que mudei o diretório?

Tenho usado muito este site que tem sido útil: http://linuxgazette.net/111/ramankutty.html mas, novamente, estou perplexo.

Obrigado pela ajuda.Deixe-me saber se devo postar algum do meu código existente, mas não tenho certeza se era necessário.

Foi útil?

Solução

Para implementar o comando cd você só precisa da chamada do sistema chdir.

#include <unistd.h>

int chdir(
    const char *path /* the path name */
);

Então você pode simplesmente chamar algo como:

int ret1 = chdir("../foo/bar");

O valor de retorno de chdir é 0 quando foi possível mudar para esse diretório e -1 se ocorreu um erro.Para o erro, você deve consolidar a página de manual.

O diretório atual pode ser verificado por qualquer programa, portanto, se você executar ls sem nenhum argumento, ls verifica em qual diretório está sendo executado e usa esse diretório como único argumento.Esta é uma característica de ls e não do execv chamar.

Para a segunda parte.

#include <unistd.h>
int execv(
     const char *path, /* programm path*/
     char *const argv[]/* argument vector*/
);

execv executa um arquivo executável no determinado path e com os argumentos dados em argv.Então, se você quiser executar /bin/ls ../foo /bar, você precisa de algo semelhante a

char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
    /* an error occurred */
}

O erro retornado por execv é -1.Se você quiser saber por que ele não executou o comando, verifique as páginas de manual.

O NULL em char *argv[] = {cmd_str, "../foo", "/bar", NULL }; existe para indicar que não há outros argumentos após o NULL.

A terceira parte.Sistemas baseados em Unix normalmente tratam comandos com / como comandos que podem ser executados diretamente.O que significa que você primeiro verifica se há uma barra na string de comando fornecida.

int ret_value;
if (strchr(cmd_str, '/')
    if (execv(cmd_str, argv) == -1 ){
        /* an error occurred */
    }

Se não houver barra, você precisará percorrer todos os diretórios em PATH e verifique se você pode executar o comando.Então o comando dado é ls ../foo /bar e vamos assumir o valor de PATH é ".:/sbin:/bin:/usr/bin".Tentaríamos então executar primeiro ./ls ../foo /bar então /usr/bin/ls ../foo /bar e finalmente /bin/ls ../foo /bar.

Espero que isto ajude.

Outras dicas

Por exemplo, se o comando for bin/ls, como é que execv conhece a exibição de todos os arquivos/pastas do diretório inicial?Como posso informar ao sistema que mudei o diretório?

Todo processo possui um diretório de trabalho atual, que pode ser modificado usando chdir.Os processos filhos herdarão o diretório de trabalho de seus pais.Então, em geral, seu shell gerenciará seu diretório de trabalho atual em resposta a cd comandos inseridos pelo usuário.Quando um comando que não é interno é inserido, você fork para criar um processo filho e depois chamar execv lá para executar o binário.

Se você quiser pegar o PATH em consideração para nomes de programas que não contêm nenhuma parte de diretório, então você deve tentar todas as combinações possíveis de um PATH elemento e o nome do programa.Você pode verificar se o arquivo nomeado existe ou simplesmente tentar executá-lo e continuar com o próximo, se falhar.Eu cai execv chamadas falharam, você terá que ligar _exit para encerrar o processo filho.

Observe que a maioria dos shells tratará qualquer comando que contenha um / como um caminho que é passado para execv diretamente.Se o caminho não começar com um /, então é um caminho relativo e o sistema operacional irá resolvê-lo em relação ao diretório de trabalho atual.Em outras palavras, o bin/ls do seu exemplo se referiria ao ls binário no bin diretório que é um subdiretório do diretório de trabalho atual.Somente comandos que não contêm nenhum / são interpretados como um comando interno (como cd) ou o nome de algum binário localizado no PATH.

O primeiro argumento a execv é o caminho conforme você o calculou.O primeiro elemento do argv list tradicionalmente é igual ao nome conforme foi inserido, ou seja,sem acréscimo PATH diretório.Após esse primeiro argumento, quaisquer parâmetros adicionais de linha de comando são passados, seguidos por um NULL para encerrar a lista.

Acho que a questão é que você acredita que o shell é responsável por fazer o trabalho de ls. ls não é realmente uma "parte" do shell (pelo menos neste caso).A concha executa um programa chamado ls.A maioria dos comentários parece explicar como encontrar ls, mas não acredito que seja sobre isso que você está confuso.

Você deve considerar cuidadosamente qual é o objetivo do shell antes de escrevê-lo.Os comentários apontaram indiretamente o fato de que o shell "simplesmente" precisa "chamar" programas como ls e chdir, não executam suas tarefas.

ls sabe por si só que, se não receber nenhum argumento, deverá listar os arquivos no diretório de trabalho atual conforme retornado por getcwd

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top