Lendo os valores da matriz conforme a entrada do usuário fornece o tamanho errado da matriz e somente -a ou -p funciona em leitura

2

Problema 1: Eu quero obter os itens da matriz como entradas do usuário em tempo de execução; imprima os itens e imprima o comprimento da matriz. Isso é o que eu tenho:

read -a myarray
echo "array items" ${myarray[@]}
echo "array length" ${#myarray[@]}

Em tempo de execução, eu dei o seguinte como entrada,

$ ("apple fruit" "orange" "grapes")

A saída foi

array items "apple fruit" "orange" "grapes"
array length 4

que não está correto.

Se eu não pedir a entrada do usuário e, em vez disso, usar uma matriz declarada e inicializada como parte do código como myarray=("apple fruit" "orange" "grapes") , o tamanho da matriz será ecoado como 3. Então, parece que o meu uso do comando read não está correto .

Problema 2: Se eu adicionar um prompt ao comando de leitura da seguinte forma,

read -p "enter array items: " myarray

o primeiro item "fruta da maçã" é impresso como fruta "e o comprimento também está errado.

Se eu remover o prompt e adicionar -a, tudo estará bem. Se eu combinar tanto aep como dar como read -ap, o prompt não aparece. Aguarda valores sem qualquer mensagem. Por que é tão? Alguém pode me explicar o que está errado?

    
por Ammu 22.08.2017 / 23:53

3 respostas

6

Problema 1:

No seu exemplo, read não recebe sua entrada de um argumento de linha de comando, mas de stdin. Como tal, a entrada que recebe não passa pelo analisador de cadeia bash . Em vez disso, ele é tratado como uma sequência literal, delimitada por espaços. Assim, com sua entrada, seus valores de matriz se tornam:

[0]->("apple
[1]->fruit"
[2]->"orange"
[3]->"grapes"

Para fazer o que você quer, você precisa escapar de todos os espaços que você tem, para evitar que o delimitador entre.. Você deve digitar a seguinte entrada após invocar read :

apple\ fruit oranges grapes

Problema 2: Para que read armazene a entrada que recebe como uma matriz, você deve ter uma opção -a seguida do nome da matriz. Então você precisa:

read -a myarray -p "Enter your items"
    
por 23.08.2017 / 00:17
3

O analisador de linha de comando do shell se preocupa com aspas duplas e simples, mas read não (portanto, não as remove também). Para read de entrada, você precisa de barras invertidas:

apple\ fruit orange grapes
    
por 23.08.2017 / 00:16
0

Se você quisesse permitir que o usuário usasse as citações de shell para delimitar os elementos (e não apenas backslash ), em zsh , você poderia fazer:

IFS= read -r 'string?Please enter the elements: '
array=("${(@XQ)${(z)string}}")
  • (z) é dividir $string em elementos como o analisador de shell faria.
  • Q para remover um nível de citação das palavras resultantes
  • X para relatar mensagens de erro na sintaxe
  • @ e as aspas para preservar os elementos vazios.

Dessa forma, o usuário pode inserir coisas como:

'first word' "second word" third\ word $'word\nwith\nnewline' ''

Tenha em atenção que, embora não exista expansão, a sintaxe do código da shell esperada não se limita à cotação. Por exemplo, $(foo bar) seria analisado em uma única palavra $(foo bar) , ${unclosed causaria um erro de sintaxe. O usuário precisaria inseri-las como '$(foo)' 'bar)' , ou '' $ {unclosed '.

    
por 23.08.2017 / 16:14