AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 449593
Accepted
JoL
JoL
Asked: 2018-06-14 08:01:39 +0800 CST2018-06-14 08:01:39 +0800 CST 2018-06-14 08:01:39 +0800 CST

A análise de scripts em tempo de execução de script é onipresente nos shells ou está presente em outros interpretadores e como isso funciona?

  • 772

Eu sempre pensei que os shells analisam scripts inteiros, construindo um AST e, em seguida, executam esse AST da memória. No entanto, acabei de ler um comentário de Stéphane Chazelas e testei a execução deste script, edit-while-executing.sh:

#!/bin/bash

echo start
sleep 10

e então enquanto ele estava dormindo correndo:

$ echo "echo end" >> edit-while-executing.sh

e funcionou para fazer com que ele imprimisse "fim" no final.

No entanto, ao tentar modificar isso:

#!/bin/bash

while true; do
  echo yes
done

fazendo:

$ printf "%s" "no " | dd of=edit-while-executing.sh conv=notrunc seek=35 bs=1

Não funcionou e continuou imprimindo "sim".

Também me perguntei se outros intérpretes não shell também funcionavam assim e tentei o equivalente ao primeiro script com python, mas não funcionou. No entanto, talvez o python não seja mais um interpretador e seja mais um compilador JIT.

Então, para reiterar minha pergunta, esse é um comportamento onipresente aos shells e limitado a eles ou também presente em outros interpretadores (aqueles que não são considerados shells)? Além disso, como isso funciona de modo que eu possa fazer a primeira modificação, mas não a segunda?

shell-script shell
  • 3 3 respostas
  • 351 Views

3 respostas

  • Voted
  1. thrig
    2018-06-14T09:10:18+08:002018-06-14T09:10:18+08:00

    Esse recurso está presente em outros intérpretes que oferecem o que é chamado de arquivo read eval print loop. LISPéuma linguagem bastante antiga com tal recurso, e o Common LISP tem uma readfunção que irá ler aqui a expressão (+ 2 2)que pode ser passada evalpara avaliação (embora no código real você não queira fazer desta forma por várias razões de segurança ):

    % sbcl
    * (defparameter sexp (read))
    (+ 2 2)
    
    SEXP
    * (print (eval sexp))
    
    4
    4
    

    também podemos definir nosso próprio REPL muito simples sem muito em termos de recursos ou depuração ou praticamente qualquer outra coisa, mas isso mostra as partes do REPL:

    * (defun yarepl () (loop (print (eval (read))) (force-output) (fresh-line)))
    
    YAREPL
    * (yarepl)
    (* 4 2)
    
    8
    (print "hi")
    
    "hi"
    "hi"
    

    Basicamente, como diz na placa de identificação, os dados são lidos, avaliados, impressos e, em seguida, (supondo que nada tenha travado e ainda haja eletricidade ou algo alimentando o dispositivo) ele volta para a leitura Não há necessidade de construir um AST com antecedência. (SBCL precisa de adições force-outpute fresh-linepor motivos de exibição, outras implementações de LISP comuns podem ou não.)

    Outras coisas com REPL incluem TCL ("um shell mordido por um LISP radioativo") que inclui coisas gráficas com Tk

    % wish
    wish> set msg "hello"
    hello
    wish> pack [label .msg -textvariable msg]
    wish> wm geometry . 500x500
    wish> exit
    

    Ou FORTH aqui para definir uma função f>cpara fazer conversão de temperatura (os "ok" são adicionados por gforth):

    % gforth
    Gforth 0.7.3, Copyright (C) 1995-2008 Free Software Foundation, Inc.
    Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
    Type `bye' to exit
    : f>c ( f -- c ) 32 - 5 9 */ cr . cr ;  ok
    -40 f>c
    -40
     ok
    100 f>c
    37
     ok
    bye
    
    • 3
  2. Best Answer
    ilkkachu
    2018-06-14T09:39:28+08:002018-06-14T09:39:28+08:00

    Então, isso é executado indefinidamente em Bash/dash/ksh/zsh (ou pelo menos até que seu disco fique cheio):

    #!/bin/sh
    s=$0
    foo() { echo "hello"; echo "foo" >> $s; sleep .1; }
    foo
    

    A coisa a notar, é que apenas coisas anexadas adicionadas ao arquivo de script após a última linha que o shell leu são importantes. Os shells não voltam para reler as partes anteriores, o que eles nem poderiam fazer, se a entrada fosse um pipe.

    A construção semelhante não funciona em Perl, ela lê o arquivo inteiro antes de ser executado.

    #!/usr/bin/perl -l    
    open $fd, ">>", $0;
    sub foo { print "hello"; print $fd 'foo;' }
    foo;
    

    Podemos ver que ele também faz isso quando recebe uma entrada por meio de um pipe. Isso dá um erro de sintaxe (e apenas isso) após 1 segundo:

    $ (echo 'printf "hello\n";' ; sleep 1 ; echo 'if' ) | perl 
    

    Enquanto o mesmo script é canalizado para, por exemplo, Bash, imprime helloe, em seguida, lança o erro de sintaxe um segundo depois.

    Python parece semelhante ao Perl com entrada canalizada, mesmo que o interpretador execute um loop read-eval-print quando interativo.


    Além de ler o script de entrada linha por linha, pelo menos Bash e dash processam argumentos para evaluma linha de cada vez:

    $ cat evaltest.sh
    var='echo hello
    fi'
    eval "$var"
    $ bash evaltest.sh
    hello
    evaltest.sh: eval: line 4: syntax error near unexpected token `fi'
    evaltest.sh: eval: line 4: `fi'
    

    Zsh e ksh dão o erro imediatamente.

    Da mesma forma para scripts de origem, desta vez o Zsh também executa linha por linha, assim como Bash e dash:

    $ cat sourceme.sh
    echo hello
    fi
    $ zsh -c '. ./sourceme.sh'
    hello
    ./sourceme.sh:2: parse error near `fi'
    
    • 2
  3. muru
    2018-06-14T08:14:21+08:002018-06-14T08:14:21+08:00

    Pelo menos uma concha, peixe, não exibe esse comportamento (mas o peixe é incomum de outras maneiras):

    % for sh in zsh mksh fish dash bash tcsh; do echo 'sleep 5' > foo.$sh; $sh foo.$sh & sleep 1; echo 'echo $0' >> foo.$sh; fg; done
    [2] 7381
    [2]  - 7381 running    $sh foo.$sh
    foo.zsh
    [2] 7385
    [2]  - 7385 running    $sh foo.$sh
    foo.mksh
    [2] 7387
    [2]  - 7387 running    $sh foo.$sh
    [2] 7390
    [2]  - 7390 running    $sh foo.$sh
    foo.dash
    [2] 7393
    [2]  - 7393 running    $sh foo.$sh
    foo.bash
    [2] 7415
    [2]  - 7415 running    $sh foo.$sh
    foo.tcsh
    

    (Uma versão anterior desta resposta tinha observações equivocadas de Python e Ruby.)

    • 1

relate perguntas

  • Um script que imprime as linhas de um arquivo com seu comprimento [fechado]

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • Como salvar um caminho com ~ em uma variável?

  • MySQL Select com função IN () com array bash

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve