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 / 460266
Accepted
Debanjan Basu
Debanjan Basu
Asked: 2018-08-04 00:55:33 +0800 CST2018-08-04 00:55:33 +0800 CST 2018-08-04 00:55:33 +0800 CST

Use read como um prompt dentro de um loop while acionado por read?

  • 772

Eu tenho um caso de uso em que preciso ler várias variáveis ​​no início de cada iteração e ler uma entrada do usuário no loop.

Possíveis caminhos para a solução que não sei como explorar -

  1. Para atribuição, use outro filehandle em vez de stdin
  2. Use um forloop em vez de ... | while read ...... Não sei como atribuir várias variáveis ​​dentro de um forloop

    echo -e "1 2 3\n4 5 6" |\
    while read a b c; 
    do 
      echo "$a -> $b -> $c";
      echo "Enter a number:";
      read d ;
      echo "This number is $d" ; 
    done
    
bash shell-script
  • 3 3 respostas
  • 9347 Views

3 respostas

  • Voted
  1. Best Answer
    ilkkachu
    2018-08-04T01:23:35+08:002018-08-04T01:23:35+08:00

    Se eu entendi direito, acho que você quer basicamente fazer um loop sobre listas de valores e depois readoutra dentro do loop.

    Aqui estão algumas opções, 1 e 2 são provavelmente as mais sensatas.

    1. Emular arrays com strings

    Ter arrays 2D seria bom, mas não é realmente possível no Bash. Se seus valores não tiverem espaço em branco, uma solução alternativa para aproximar isso é colocar cada conjunto de três números em uma string e dividir as strings dentro do loop:

    for x in "1 2 3" "4 5 6"; do 
      read a b c <<< "$x"; 
      read -p "Enter a number: " d
      echo "$a - $b - $c - $d ";
    done
    

    Claro que você também pode usar algum outro separador, por exemplo for x in 1:2:3 ...e IFS=: read a b c <<< "$x".


    2. Substitua o pipe por outro redirecionamento para free stdin

    Outra possibilidade é fazer a read a b cleitura de outro fd e direcionar a entrada para isso (isso deve funcionar em um shell padrão):

    while read a b c <&3; do
        printf "Enter a number: "
        read d
        echo "$a - $b - $c - $d ";
    done 3<<EOF
    1 2 3
    4 5 6
    EOF
    

    E aqui você também pode usar uma substituição de processo se quiser obter os dados de um comando: while read a b c <&3; ...done 3< <(echo $'1 2 3\n4 5 6')(a substituição de processo é um recurso bash/ksh/zsh)


    3. Em vez disso, obtenha a entrada do usuário do stderr

    Ou, ao contrário, usando um pipe como no seu exemplo, mas faça com que o usuário insira readde stderr(fd 2) em vez de stdinonde o pipe vem:

    echo $'1 2 3\n4 5 6' |
    while read a b c; do 
        read -u 2 -p "Enter a number: " d
        echo "$a - $b - $c - $d ";
    done
    

    Ler de stderré um pouco estranho, mas na verdade geralmente funciona em uma sessão interativa. (Você também pode abrir explicitamente /dev/tty, supondo que deseja realmente ignorar qualquer redirecionamento, é isso que lessusa para obter a entrada do usuário, mesmo quando os dados são canalizados para ele.)

    Embora usar stderrassim possa não funcionar em todos os casos, e se você estiver usando algum comando externo em vez de read, precisará pelo menos adicionar vários redirecionamentos ao comando.

    Além disso, consulte Por que minha variável é local em um loop 'enquanto lido', mas não em outro loop aparentemente semelhante? para algumas questões sobre ... | while.


    4. Fatie partes de uma matriz conforme necessário

    Suponho que você também possa aproximar uma matriz 2D copiando fatias de uma unidimensional regular:

    data=(1 2 3 
          4 5 6)
    
    n=3
    for ((i=0; i < "${#data[@]}"; i += n)); do
        a=( "${data[@]:i:n}" )
        read -p "Enter a number: " d
        echo "${a[0]} - ${a[1]} - ${a[2]} - $d "
    done
    

    Você também pode atribuir ${a[0]}etc. a a, betc se quiser nomes para as variáveis, mas Zsh faria isso muito mais bem .

    • 13
  2. user232326
    2018-08-04T20:42:16+08:002018-08-04T20:42:16+08:00

    Existe apenas um /dev/stdin, readserá lido em qualquer lugar onde for usado (por padrão).

    A solução é usar algum outro descritor de arquivo em vez de 1 ( /dev/stdin).

    Do código equivalente (no bash) ao que você postou [1] (veja abaixo)
    , basta adicionar 0</dev/tty(por exemplo) para ler do tty "real":

    while read a b c
    do    read -p "Enter a number: " d  0</dev/tty   # 0<&2 is also valid
          echo "$a -> $b -> $c and ++> $d"
    done  <<<"$(echo -e '1 2 3\n4 5 6')"
    

    Na execução:

    $ ./script
    Enter a number: 789
    1 -> 2 -> 3 and ++> 789
    Enter a number: 333
    4 -> 5 -> 6 and ++> 333
    

    Outra alternativa é usar 0<&2(o que pode parecer estranho, mas é válido).

    Observe que a leitura de /dev/tty(também 0<&2) ignorará o stdin do script, isso não lerá os valores do echo:

    $ echo -e "33\n44" | ./script
    

    Outras soluções

    O que é necessário é redirecionar uma entrada para algum outro fd (descritor de arquivo).
    Válido em ksh, bash e zsh:

    while read -u 7 a b c
    do    printf "Enter a number: "
          read d
          echo "$a -> $b -> $c and ++> $d"
    done  7<<<"$(echo -e '1 2 3\n4 5 6')"
    

    Ou, com exec:

    exec 7<<<"$(echo -e '1 2 3\n4 5 6')"
    
    while read -u 7 a b c
    do    printf "Enter a number: "      
          read d
          echo "$a -> $b -> $c and ++> $d"
    done  
    
    exec 7>&-
    

    Uma solução que funciona em sh ( <<<não funciona):

    exec 7<<-\_EOT_
    1 2 3
    4 5 6
    _EOT_
    
    while read a b c  <&7
    do    printf "Enter a number: "      
          read d
          echo "$a -> $b -> $c and ++> $d"
    done  
    
    exec 7>&-
    

    Mas isso provavelmente é mais fácil de entender:

    while read a b c  0<&7
    do    printf "Enter a number: "      
          read d
          echo "$a -> $b -> $c and ++> $d"
    done  7<<-\_EOT_
    1 2 3
    4 5 6
    _EOT_
    

    1 código mais simples

    Seu código é:

    echo -e "1 2 3\n4 5 6" |\
    while read a b c; 
    do 
      echo "$a -> $b -> $c";
      echo "Enter a number: ";
      read d ;
      echo "This number is $d" ; 
    done
    

    Um código simplificado (em bash) é:

    while read a b c
    do    #0</dev/tty
          read -p "Enter a number: " d ;
          echo "$a -> $b -> $c and ++> $d";
    done  <<<"$(echo -e '1 2 3\n4 5 6')"
    

    Que, se executado, imprime:

    $ ./script
    1 -> 2 -> 3 and ++> 4 5 6
    

    O que está apenas mostrando que o var d está sendo lido do mesmo /dev/stdin.

    • 5
  3. Stéphane Chazelas
    2018-08-04T03:10:32+08:002018-08-04T03:10:32+08:00

    Com zsh, você pode escrevê-lo em vez disso:

    for a b c (
      1 2 3
      4 5 6
      'more complex' $'\n\n' '*** values ***'
    ) {
      read 'd?Enter a number: '
      do-something-with $a $b $c $d
    }
    

    Para arrays 2D, veja também o ksh93shell:

    a=(
      (1 2 3)
      (4 5 6)
      ('more complex' $'\n\n' '*** values ***')
    )
    for i in "${!a[@]}"; do
      read 'd?Enter a number: '
      do-something-with "${a[i][0]}" "${a[i][1]}" "${a[i][2]}" "$d"
    done
    
    • 2

relate perguntas

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

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

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

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