O comportamento do CDPATH está quebrado no shell do bourne (/ bin / sh)

0

Eu tenho o seguinte script:

#!/bin/sh

mkdir -p /tmp/test/foo

cd /tmp/test

unset CDPATH
echo "TEST1: Current working directory: ${PWD}"
echo "TEST1: attempting to 'cd foo'"
cd foo
echo "TEST1: Current working directory: ${PWD}"

cd /tmp/test
CDPATH=/tmp
echo "TEST2: Current working directory: ${PWD}"
echo "TEST2: attempting to 'cd foo'"
cd foo
echo "TEST2: Current working directory: ${PWD}"

Que imprime:

$ ./cdpath.sh
TEST1: Current working directory: /tmp/test
TEST1: attempting to 'cd foo'
TEST1: Current working directory: /tmp/test/foo
TEST2: Current working directory: /tmp/test
TEST2: attempting to 'cd foo'
./cdpath.sh: line 17: cd: foo: No such file or directory
TEST2: Current working directory: /tmp/test

No entanto, se eu executar como /bin/bash cdpath.sh , não haverá erro e a saída TEST2 será idêntica a TEST1 . O erro só ocorre se eu executar com /bin/sh . Eu não encontrei nenhuma documentação sobre bourne e Bourne interpretando o CDPATH diferentemente:

link link

    
por onlynone 27.01.2014 / 20:25

2 respostas

3

Depois de muito mais pesquisa e verificação de código-fonte descobri a razão pela qual estou vendo esse comportamento é que estou executando o bash 3.2. Nesta versão do bash, se você estava executando no modo posix (que acontece quando você executa o bash através de /bin/sh ) e CDPATH está definido, então cd não pesquisará o diretório atualmente, a menos que seja explicitamente definido em CDPATH . Esse comportamento foi incluído para estar de acordo com POSIX.2 ( IEEE 1003.2-1992 ). Isso reflete o que seu manual especificado no momento . No entanto, para o bash 4.2, eles alteraram o comportamento no modo posix para corresponder ao POSIX.1-2008 atualizado, que agora especifica que cd sempre deve pesquisar o diretório de trabalho atual, mesmo se CDPATH não o incluir. Novo manual do Bash agora não inclui mais isso como uma diferença entre os modos posix e non-posix porque não é mais diferente.

Eles fizeram a alteração desabilitando o código que gera um erro se o modo posix estiver ativado, cercando-o com um bloco #if 0 em builtins/cd.def :

#if 0
      /* changed for bash-4.2 Posix cd description steps 5-6 */
      /* POSIX.2 says that if '.' does not appear in $CDPATH, we don't
         try the current directory, so we just punt now with an error
         message if POSIXLY_CORRECT is non-zero.  The check for cdpath[0]
         is so we don't mistakenly treat a CDPATH value of "" as not
         specifying the current directory. */
      if (posixly_correct && cdpath[0])
        {
          builtin_error ("%s: %s", dirname, strerror (ENOENT));
          return (EXECUTION_FAILURE);
        }
#endif

Eu gostaria que os docs atuais do bash notassem o fato de que versões mais antigas do bash tinham esse comportamento.

    
por 27.01.2014 / 22:07
2

O shell Bourne original ( /bin/sh ) não tinha CDPATH . Essa foi uma das inovações do Kornshell que mais tarde foi adicionada ao padrão POSIX e depois se embotou. Como isso é implementado, diferem do shell para o shell e do modo em que o shell está.

Em muitos sistemas, /bin/sh é um link físico para /bin/bash , mas o bash altera seu comportamento quando chamado como sh em vez de bash . A partir da manch bash:

If bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well. When invoked as an interactive login shell, or a non-interactive shell with the --login option, it first attempts to read and execute commands from /etc/profile and ~/.profile, in that order.

Em alguns sistemas, /bin/sh é, na verdade, o shell ' que desce do cinzas .

Assim, a diferença que você está vendo pode ser devido ao modo como o bash funciona quando está sendo bash, o bash funciona quando está operando no modo de compatibilidade POSIX ou quando você está usando dash ou ash em vez de bash , que pode ou não implementar o CDPATH de uma forma única.

Ao usar um shell compatível com POSIX, o diretório . não é incluído automaticamente em CDPATH . No entanto, se um shell não for completamente compatível com POSIX, ele poderá incluir automaticamente . no CDPATH para você.

Encontrei esta informação no Softpanorama :

Warning: Watch out when running bash in POSIX mode (e.g., as /bin/sh or with --posix). As the bash Reference notes:"If $CDPATH is set, the cd built-in will not implicitly append the current directory to it. This means that cd will fail if no valid directory name can be constructed from any of the entries in $CDPATH, even if a directory with the same name as the name given as an argument to cd exists in the current directory.

"To avoid this, explicitly include . in $CDPATH. However, if you do that, then another subtle point noted in the bash Reference comes into play:"If a nonempty directory name from $CDPATH is used, or if '-' is the first argument, and the directory change is successful, the absolute pathname of the new working directory is written to the standard output."In other words, pretty much every time you use cd it will echo the new path to STDOUT, which is not the standard behavior.

    
por 27.01.2014 / 20:52