comm falha na entrada da variável bash

3

Eu tenho um script que deve obter a lista de arquivos de dois diretórios, obter diferenças e executar algum código para determinados arquivos.

Estes são os comandos para obter as listas de arquivos:

list_in=$(find input/ -maxdepth 1 - type f | sed 's/input\///' | sort -u);
list_out=$(find output/ -maxdepth 1 - type f | sed 's/output\///' | sort -u);

Eu executo o script no diretório correto, então isso não deve falhar. Os arquivos não processados são determinados por

list_todo=$(comm -23 <(echo "$list_in") <(echo "$list_out"));

desde que a opção -23 para comm imprime somente linhas do primeiro argumento, que não aparecem em ambos os argumentos e não imprime linhas que aparecem exclusivamente no segundo argumento.

No entanto, só ocasionalmente recebo um erro dizendo

command substitution: line 3: syntax error near unexpected token '('
command substitution: line 3: 'comm -23 <(echo "$list_in") <(echo "$list_out")'

Isso realmente me intriga, já que o mesmo script funcionou bem nas últimas 3 semanas. Estou usando isso em um cluster, então vários processos podem executar o script simultaneamente. O erro pode ser causado por isso?

Atualizar . O script é chamado com ./script e, obviamente, eu defini chmod +x script antes.

(Aviso: Embora eu esteja trabalhando em um cluster e essas três primeiras linhas do meu script não incluam mecanismos de bloqueio: claro, nenhum arquivo é processado duas vezes)

    
por stefan 15.01.2013 / 18:35

2 respostas

3

O kernel reconhece certos formatos de arquivo que podem ser executados nativamente. Isso inclui pelo menos um formato binário. Além disso, os arquivos que começam com #! ( shebang ) são considerados scripts; por exemplo, se um arquivo estiver localizado em /path/to/script e começar com #!/bin/bash , o kernel executará /bin/bash /path/to/script arg1 arg2 quando você invocar /path/to/script arg1 arg2 .

Se o kernel não reconhecer o formato do arquivo, ele retornará ENOEXEC (erro de formato exec) do execve chamada do sistema. Seguindo uma tradição dos antigos kernels Unix que não tinham o recurso shebang, a maioria dos programas faz uma segunda tentativa de executar um programa quando a primeira tentativa falha com o erro ENOEXEC: eles tentam executar /bin/sh como o intérprete de script .

Bash é uma exceção notável: ele executa o script em si, não em /bin/sh . Então o seu script estava funcionando por acidente quando você o invocou do bash.

Se você deixar a linha shebang, seu script pode ser executado em /bin/bash ou sob /bin/sh , dependendo de qual programa foi executado. E /bin/sh evidentemente não suporta a substituição de processos no seu sistema. Provavelmente ainda é bash (a mensagem de erro parece com a do bash), mas quando o bash é invocado sob o nome sh , ele entra no modo de compatibilidade POSIX que não suporta a substituição do processo.

A moral da história: se você escrever um script bash, deverá colocar #!/bin/bash na primeira linha.

    
por 16.01.2013 / 01:42
1

A construção $ () e < () é apenas bash. Isso significa que você precisa que sua linha de shebang seja:

#!/bin/bash

Particularmente, isso não funcionará:

#!/bin/sh

Se você precisar trabalhar com sh , poderá usar 'em vez de $ ():

list_in='find input/ -maxdepth 1 - type f | sed 's/input\///' | sort -u'

Você pode usar o mkfifo no lugar de < ().

    
por 15.01.2013 / 20:06