A linha Shebang com o comando `#! / Usr / bin / env --argument` falha no Linux

53

Eu tenho um script simples:

#!/usr/bin/env ruby --verbose
# script.rb
puts "hi"

Na minha caixa OSX, ele funciona bem:

osx% ./script.rb
hi

No entanto, na minha caixa linux, gera um erro

linux% ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory

Se eu executar a linha shebang manualmente, funcionará bem

linux% /usr/bin/env ruby --verbose ./script.rb
hi

Mas eu posso replicar o erro se eu agrupar ruby --verboseem um único argumento paraenv

linux% /usr/bin/env "ruby --verbose" ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory

Então, acho que esse é um problema de como envestá interpretando a redefinição da linha shebang. Estou usando o GNU coreutils 8.4 env:

linux% /usr/bin/env --version
env (GNU coreutils) 8.4
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Richard Mlynarik and David MacKenzie.

Isso parece realmente estranho. Esse é um problema comum com esta versão envou há algo mais acontecendo aqui que eu não conheço?

rampion
fonte
4
relevante?
Rampion
O mesmo aqui com coreutils 8.17. Esquisito. Reporte ao Fedora, pois isso vai explicitamente contra o que o manual diz.
22613 vonbrand
@vonbrand O que o Fedora disse? "Nós não nos importamos."
gato

Respostas:

44

Parece que isso ocorre porque o Linux (ao contrário do BSD) passa apenas um único argumento para o comando shebang (neste caso, env).

Isso foi discutido extensivamente no StackOverflow .

rampion
fonte
3
veja também esta página para uma revisão do comportamento em diferentes Unices.
Stéphane Chazelas
4
Falha na especificação. Meu Deus.
Konrad Rudolph
3
Se por "especificação falhar" você quer dizer todos os sistemas Unix devem aceitar mais de 1 argumento, então eu concordo 100% com você :)
Alexander Mills
Não tanto 'linux' como GNU.
será
5

Encontrei este comentário via @rampion:

O que acontece é que o kernel processa os dois primeiros caracteres do arquivo procurando por # !. Se esses forem encontrados, ele pula todos os caracteres de espaço que procuram um caracter não-espacial e extrai o caminho do interpretador, que deve ser um executável real e não outro script, embora o linux o estenda para permitir o processamento recursivo de scripts. Tendo descoberto isso, ele pula para o primeiro caractere não espacial, de onde passa para o próximo caractere de nova linha e passa isso como um único argumento para o comando. Não há processamento 'shell' de aspas ou outros meta caracteres. É tudo força muito simples e bruta. Portanto, você não pode gostar de opções lá. Você inclui exatamente um espaço em branco de argumento e 'perl -w' é o que o kernel vê aqui e passa adiante.

Fonte: http://lists.gnu.org/archive/html/bug-sh-utils/2002-04/msg00020.html

Aalex Gabi
fonte