Por que o zsh abre um descritor de arquivo em um?

3

Eu posso abrir um descritor de arquivo explicitamente da maneira normal:

$ ls -lh /dev/fd/
total 0
lrwx------ 1 tavianator users 64 Jul 10 11:06 0 -> /dev/pts/6
lrwx------ 1 tavianator users 64 Jul 10 11:06 1 -> /dev/pts/6
lrwx------ 1 tavianator users 64 Jul 10 11:06 2 -> /dev/pts/6
lr-x------ 1 tavianator users 64 Jul 10 11:06 3 -> /proc/31288/fd
$ exec 3<foo
$ ls -lh /dev/fd/
total 0
lrwx------ 1 tavianator users 64 Jul 10 11:07 0 -> /dev/pts/6
lrwx------ 1 tavianator users 64 Jul 10 11:07 1 -> /dev/pts/6
lrwx------ 1 tavianator users 64 Jul 10 11:07 2 -> /dev/pts/6
lr-x------ 1 tavianator users 64 Jul 10 11:07 3 -> /home/tavianator/foo
lr-x------ 1 tavianator users 64 Jul 10 11:07 4 -> /proc/31334/fd

Até aí tudo bem. zsh parece não suportar a sintaxe do descritor de arquivo de dois dígitos como 10<foo , mas suporta uma sintaxe de substituição de variável {fd}<foo :

$ fd=10
$ exec {fd}<foo
$ ls -lh /dev/fd/
total 0
lrwx------ 1 tavianator users 64 Jul 10 11:08 0 -> /dev/pts/6
lrwx------ 1 tavianator users 64 Jul 10 11:08 1 -> /dev/pts/6
lr-x------ 1 tavianator users 64 Jul 10 11:08 11 -> /home/tavianator/foo
lrwx------ 1 tavianator users 64 Jul 10 11:08 2 -> /dev/pts/6
lr-x------ 1 tavianator users 64 Jul 10 11:08 3 -> /home/tavianator/foo
lr-x------ 1 tavianator users 64 Jul 10 11:08 4 -> /proc/31413/fd

Mas, por que fd 11 é aberto em vez de 10 ?

    
por Tavian Barnes 10.07.2017 / 17:18

1 resposta

3

Porque é assim que o ZSH é escrito. ZSH por padrão duplica um descritor de arquivo para fd 10:

$ PS1='%% ' zsh -f
% lsof -p $$ | grep 10u
zsh     29192 jhqdoe   10u   CHR  136,0       0t0         3 /dev/pts/0
% 

E código relacionado a fd subsequente em Src/exec.c chamadas movefd

/**/
static void
addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag,
      char *varid)
{
    int pipes[2];

    if (varid) {
        /* fd will be over 10, don't touch mfds */
        fd1 = movefd(fd2);
        if (fd1 == -1) {
            zerr("cannot moved fd %d: %e", fd2, errno);
            return;

que em Src/utils.c a duplicata-para-a-próxima-disponível-acima-10-que-já-foi-tomada-por-padrão-assim-a-primeira-você-verá-é -11 coisa:

movefd(int fd)
{
    if(fd != -1 && fd < 10) {
#ifdef F_DUPFD
        int fe = fcntl(fd, F_DUPFD, 10);
#else
        int fe = movefd(dup(fd));
#endif

Meu zsh de acordo com strace está usando o caminho do código fcntl , embora eu suspeite dos comentários de que fcntl(... ou movefd(dup(... resultará em novo fd começando em 11; 10 não está disponível, pois o zsh, por padrão, contém uma duplicata nesse número.

Tudo o que o {somelabel} faz é obter o menor descritor de arquivo disponível maior que 10; isso pode ser 11 ou pode ser um número maior dependendo do que mais o shell já tem aberto:

% exec {foo}>asdf
% echo $foo
11
% exec {quer}>asdf
% echo $quer
12
...
    
por 10.07.2017 / 18:23