É portável para executar um comando na mesma linha após a atribuição da variável?

7

Existe algum padrão que cubra a portabilidade de executar um comando após a atribuição de variáveis na mesma linha?

APPLE="cider" echo hi

Quão portátil é algo assim? Onde vai funcionar e onde não vai?

Além disso: meus scripts de shell começam com #! / bin / sh se isso faz alguma diferença.

    
por test 23.10.2013 / 20:10

4 respostas

6

Contanto que você esteja usando um shell compatível com POSIX, sim.

Da definição POSIX da linguagem de comandos shell : (pontos relevantes em negrito)

A "simple command" is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator.

When a given simple command is required to be executed (that is, when any conditional construct such as an AND-OR list or a case statement has not bypassed the simple command), the following expansions, assignments, and redirections shall all be performed from the beginning of the command text to the end:

  1. The words that are recognized as variable assignments or redirections according to Shell Grammar Rules are saved for processing in steps 3 and 4.

  2. The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first field shall be considered the command name and remaining fields are the arguments for the command.

  3. Redirections shall be performed as described in Redirection.

  4. Each variable assignment shall be expanded for tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal prior to assigning the value.

In the preceding list, the order of steps 3 and 4 may be reversed for the processing of special built-in utilities; see Special Built-In Utilities.

If no command name results, variable assignments shall affect the current execution environment. Otherwise, the variable assignments shall be exported for the execution environment of the command and shall not affect the current execution environment (except for special built-ins).

Além disso, sim #!/bin/sh é importante. Da definição POSIX de sh :

The sh utility is a command language interpreter that shall execute commands read from a command line string, the standard input, or a specified file. The application shall ensure that the commands to be executed are expressed in the language described in Shell Command Language.

Então basicamente diz que sh deve seguir as regras que abordamos acima.

Assim, enquanto você estiver em um sistema operacional compatível com POSIX, você é bom.

    
por 24.10.2013 / 06:50
3

Para responder a segunda pergunta, incompletamente (o número de shells é mindboggling )

% for sh in dash ksh93 mksh rc fish bash zsh csh tcsh jsh; do
printf '%s\n' "$sh: $($sh -c 'var=foo echo hi')"
done

dash: hi
ksh93: hi
mksh: hi
rc: hi
fish: Unknown command “var=foo”. Did you mean “set var foo”? For information on assigning values to variables, see the help section on the set command by typing “help set”
Standard input: var=foo echo hi
                ^
fish:
bash: hi
zsh: hi
var=foo: Command not found.
csh:
var=foo: Command not found.
tcsh:
jsh: hi

Na maioria dos modernos Korn-like shells, funcionará. Mas eu não acho que é um padrão, tenho certeza que alguém como Stephane Chazelas saberia exatamente como comum é.

    
por 23.10.2013 / 20:46
2

Sim, tem sido assim desde os primeiros dias de sh

link

The environment for any simple-command may be
augmented by prefixing it with  one  or more
assignments to parameters.  Thus these two lines
are equivalent

      TERM=450 cmd args
      (export TERM; TERM=450; cmd args)
    
por 24.10.2013 / 05:32
2

Dado o comando em seu exemplo, echo será executado, mas o que acontece com $APPLE é um pouco mais complicado.

É verdade, como é indicado na resposta de @ Patrick aqui, que se o shell invocar um processo, todas as variáveis declaradas na linha de comando precedendo sua invocação serão especificadas para serem exportadas para seu ambiente. E, além disso, essas variáveis também são especificadas para expirar com o processo chamado - então ...

unset var; var=val cmd; echo ${var-unset.}

... deve imprimir unset.

Mas onde todo esse conceito fica um pouco mais complicado, e como seu próprio exemplo demonstra, é no ponto em que cmd não é um processo chamado, mas é em vez disso , uma função de shell ou um utilitário embutido de shell especial . Em cada um desses três casos, o shell provavelmente executará algumas de suas próprias rotinas na memória e não invocará nada.

Por exemplo, echo é quase definitivamente um utilitário interno do shell - como a maioria dos shells que eu conheço fornece como tal - mas não é especificada por POSIX especial incorporado. Desta forma, é basicamente uma função de shell que deve emular um executável externo. Provavelmente, isso é um pouco mais claro aqui:

The term "built-in" implies that the shell can execute the utility directly and does not need to search for it. An implementation may choose to make any utility a built-in; however, the special built-in utilities described here differ from regular built-in utilities...

Variable assignments specified with special built-in utilities remain in effect after the built-in completes; this shall not be the case with a regular built-in or other utility.

The special built-in utilities in this section need not be provided in a manner accessible via the exec family of functions defined in the System Interfaces volume of POSIX.1-2008.

Portanto, uma variável declarada na linha de comando echo perece com echo , mas uma declarada na linha de comando set persiste - (embora bash por padrão viole essa regra) . O mesmo acontece quando cmd é uma função shell :

When a function is executed, it shall have the syntax-error and variable-assignment properties described for special built-in utilities in the enumerated list at the beginning of Special Built-In Utilities.

    
por 06.08.2014 / 01:20

Tags