GNU/Linux >> Znalost Linux >  >> Linux

Aritmetický výraz v přesměrování

Nemám konkrétní citaci, proč toto chování existuje, ale když vyjdeme z poznámek v SC2257*, v manuálu je třeba poznamenat několik zajímavých bodů.

Když jednoduchý příkaz jiný než vestavěná nebo shellová funkce má být spuštěn, je vyvolán v samostatném prováděcím prostředí
§3.7.3 Prostředí provádění příkazů

To odráží to, co poznamenává SC2257, i když není jasné, ve kterém prostředí je hodnota přesměrování vyhodnocena. Zdá se však, že §3.1.1 Shell Operation říká, že k přesměrování dojde před toto prováděcí (pod)prostředí je vyvoláno:

V podstatě shell dělá následující:
...

  1. Provádí různé expanze shellu....
  2. Provede všechna nezbytná přesměrování a odstraní operátory přesměrování a jejich operandy ze seznamu argumentů.
  3. Provede příkaz.

Vidíme, že to není omezeno na aritmetické expanze, ale také další expanze měnící stav, jako je := :

$ bash -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=

$ bash -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow

Zajímavé je, že to nevypadá jako (dobře definované) prostředí subshell, protože BASH_SUBSHELL zůstane nastavena na 0 :

$ date >"${word:=$BASH_SUBSHELL}.txt"; ls
0.txt

Můžeme také zkontrolovat některé další shelly a uvidíme, že zsh má stejné chování, ačkoli dash ne:

$ zsh -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=

$ zsh -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow

$ dash -c 'date >"${word:=wow}.txt"; echo "word=${word}"'
word=wow

$ dash -c 'echo >"${word:=wow}.txt"; echo "word=${word}"'
word=wow

Přečetl jsem zsh průvodce, ale ani tam jsme nenašli přesnou zmínku o tomto chování.

Netřeba říkat , nezdá se, že by to bylo dobře zdokumentované chování, takže je štěstí, že ShellCheck může pomoci to zachytit. Zdá se však, že jde o dlouhodobé chování, je reprodukovatelné v Bash 3, 4 a 5.

* Potvrzení, které přidalo SC2257, bohužel neodkazuje na problém ani žádný další kontext.


Rada Shellchecku je správná; někdy se přesměrování provádějí v subshellech. Jádrem tohoto chování je však kdy dochází k expanzím:

bind_int_variable          variables.c:3410    cnt = 2, late binding
expr_bind_variable         expr.c:336          
exp0                       expr.c:1040         
exp1                       expr.c:1007         
exppower                   expr.c:962          
expmuldiv                  expr.c:887          
exp3                       expr.c:861          
expshift                   expr.c:837          
exp4                       expr.c:807          
exp5                       expr.c:785          
expband                    expr.c:767          
expbxor                    expr.c:748          
expbor                     expr.c:729          
expland                    expr.c:702          
explor                     expr.c:674          
expcond                    expr.c:627          
expassign                  expr.c:512          
expcomma                   expr.c:492          
subexpr                    expr.c:474          
evalexp                    expr.c:439          
param_expand               subst.c:9498        parameter expansion, including arith subst
expand_word_internal       subst.c:9990        
shell_expand_word_list     subst.c:11335       
expand_word_list_internal  subst.c:11459       
expand_words_no_vars       subst.c:10988       
redirection_expand         redir.c:287         expansions post-fork()
do_redirection_internal    redir.c:844         
do_redirections            redir.c:230         redirections are done in child process
execute_disk_command       execute_cmd.c:5418  fork to run date(1)
execute_simple_command     execute_cmd.c:4547  
execute_command_internal   execute_cmd.c:842   
execute_command            execute_cmd.c:394   
reader_loop                eval.c:175          
main                       shell.c:805         

Když se zavolá příkaz execute_disk_command(), rozdělí se a poté provede date(1). Po fork() a před execve() se provedou přesměrování a další rozšíření (prostřednictvím do_redirections()). Proměnné expandované a vázané po rozvětvení se neodrazí v nadřazeném shellu.

Z pohledu BASH je to však spíše jednoduchý příkaz než příkaz subshell. Toto je implicitní podshell.

Viz execute_disk_command() v execute_cmd.c

Execute a simple command that is hopefully defined in a disk file
somewhere.
1) fork ()
2) connect pipes
3) look up the command
4) do redirections
5) execve ()
6) If the execve failed, see if the file has executable mode set.
If so, and it isn't a directory, then execute its contents as
a shell script.

(odkazy převzaty z potvrzení 9e49d343e3cd7e20dad1b86ebfb764e8027596a7 [procházet strom])


Linux
  1. Použít $[ Expr ] místo $(( Expr ))?

  2. Selhalo přesměrování na název souboru Globbed?

  3. Definice regulárního výrazu?

  1. Bash + Ověřit název regulárním výrazem?

  2. Bash Tcp Redirection Konec přenosu?

  3. 6 Bashových příkladů podmíněných výrazů ( -e, -eq, -z, !=, [, [[ ..)

  1. 5 užitečných způsobů, jak provádět aritmetiku v terminálu Linux

  2. gzip - přesměrování nebo potrubí?

  3. Řešič výrazů z příkazového řádku?