Por que esse script funciona no terminal, mas não em um arquivo?

16

Eu tenho este script de shell salvo em um arquivo: ele faz alguma substituição básica de string.

#!/bin/sh
html_file=$1
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"

Se eu colá-lo na linha de comando, tudo funciona bem:

$ html_file="/home/max/for_pauld/test_no_base64.html"
  echo "html_file = $html_file"
  substr=.pdf
  pdf_file="${html_file/.html/.pdf}"
  echo "pdf_file = $pdf_file"

html_file = /home/max/for_pauld/test_no_base64.html
pdf_file = /home/max/for_pauld/test_no_base64.pdf

Essa é a saída do eco acima - está funcionando conforme o esperado.

Mas, quando eu chamo o script, com

$ saucer "/home/max/for_pauld/test_no_base64.html"

Eu recebo esta saída:

html_file = /home/max/for_pauld/test_no_base64.html
/home/max/bin/saucer: 5: /home/max/bin/saucer: Bad substitution

O meu script está usando uma versão diferente do bash ou algo assim? Preciso mudar minha linha de shebang?

    
por Max Williams 19.07.2017 / 09:40

2 respostas

34

O que é sh

sh (ou a Linguagem de Comandos da Shell) é uma linguagem de programação descrita pelo POSIX padrão . Tem muitas implementações ( ksh88 , dash , ...). bash também pode ser considerada uma implementação de sh (veja abaixo).

Como sh é uma especificação, não uma implementação, /bin/sh é um link simbólico (ou um link físico) para uma implementação real na maioria dos sistemas POSIX.

O que é bash

bash começou como uma implementação sh -compatible (embora anteceda o padrão POSIX em alguns anos), mas com o passar do tempo adquiriu muitas extensões. Muitas dessas extensões podem alterar o comportamento de scripts de shell POSIX válidos, portanto, por si só bash não é um shell POSIX válido. Pelo contrário, é um dialeto da linguagem shell POSIX.

bash suporta uma opção --posix , o que a torna mais compatível com POSIX. Ele também tenta imitar POSIX se invocado como sh .

sh = bash?

Por muito tempo, /bin/sh costumava apontar para /bin/bash na maioria dos sistemas GNU / Linux. Como resultado, quase se tornou seguro ignorar a diferença entre os dois. Mas isso começou a mudar recentemente.

Alguns exemplos populares de sistemas em que /bin/sh não aponta para /bin/bash (e em alguns dos quais /bin/bash podem nem existir) são:

  1. Sistemas Debian e Ubuntu modernos, que ligam sh a dash por padrão;
  2. Busybox , que geralmente é executado durante o tempo de inicialização do sistema Linux como parte de initramfs . Ele usa a implementação do shell ash .
  3. BSDs e, em geral, quaisquer sistemas não-Linux. O OpenBSD usa pdksh , um descendente do shell Korn. O sh do FreeBSD é um descendente do shell Bourne do UNIX original. O Solaris possui seu próprio sh , que por um longo tempo não era compatível com POSIX; uma implementação gratuita está disponível no projeto Heirloom .

Como você pode descobrir para que /bin/sh aponta no seu sistema?

A complicação é que /bin/sh poderia ser um link simbólico ou um link físico. Se for um link simbólico, uma maneira portátil de resolvê-lo é:

% file -h /bin/sh
/bin/sh: symbolic link to bash

Se for um link físico, tente

% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash

Na verdade, o sinalizador -L abrange os links simbólicos e os links físicos, mas a desvantagem desse método é que ele não é portátil POSIX não requer find para suportar a opção -samefile , embora ambos os GNU encontrem e FreeBSD encontra apoiá-lo.

Linha Shebang

Por fim, cabe a você decidir qual usar, escrevendo a linha «shebang».

Por exemplo,

#!/bin/sh

usará sh (e seja lá o que isso apontar),

#!/bin/bash

usará /bin/bash se estiver disponível (e falhará com uma mensagem de erro, se não estiver). Claro, você também pode especificar outra implementação, por exemplo,

#!/bin/dash

Qual deles usar

Para meus próprios scripts, prefiro sh pelos seguintes motivos:

  • é padronizado
  • é muito mais simples e fácil de aprender
  • é portátil em sistemas POSIX - mesmo que eles não tenham bash , eles precisam ter sh

Há vantagens em usar bash também. Suas características tornam a programação mais conveniente e semelhante à programação em outras linguagens de programação modernas. Isso inclui coisas como variáveis locais e matrizes com escopo definido. A planície sh é uma linguagem de programação muito minimalista.

    
por 19.07.2017 / 10:02
23

Com a excelente resposta do @ Hunter.S.Thompson, gostaria de salientar que a parte não-portátil do script é

pdf_file="${html_file/.html/.pdf}"

O ${variable/search/replace} é uma extensão do GNU. Mas você pode facilmente evitá-lo com o POSIX puro:

pdf_file="${html_file%.html}".pdf

Seguindo o Hunter, essa é a melhor solução do que mudar o shebang para #! /bin/bash

    
por 19.07.2017 / 11:34

Tags