Eu tenho um script onde quero listar dispositivos USB usando o comando lsblk
.
O comando:
$ lsblk -o NAME,TRAN,VENDOR,MODEL | grep usb
o que resulta em
sdb usb Kingston DataTraveler 2.0
sdc usb Kingston DT 101 G2
Eu quero salvar o resultado em uma variável para trabalhar mais tarde, então escrevo
$ usbs=$(lsblk -o NAME,TRAN,VENDOR,MODEL | grep usb)
O que eu esperava é que a variável usbs
armazenasse o resultado em duas linhas inteiras como acima. Mas se eu executar:
for i in ${usbs[@]}; do
echo $i
done
Eu recebo o resultado dividido em palavras:
sdb
usb
Kingston
DataTraveler
2.0
sdc
usb
Kingston
DT
101
G2
Pergunta:
Existe uma maneira de, usando o grep
comando, eu poder armazenar o resultado do comando como duas linhas inteiras?
Prefiro saber se existe uma solução simples em vez de despejar o resultado em um arquivo e depois lê-lo.
Esta é uma boa situação para usar readarray/mapfile :
Isso criará um array com sua saída onde cada linha é separada em seu próprio elemento.
No seu caso, faria um array como:
Como está, você está atribuindo toda a sua saída a uma única variável (não a uma matriz) que essencialmente faz isso:
Para torná-lo um array, você faria:
mas isso faria com que cada palavra fosse separada por espaço em branco em seu próprio elemento, equivalente a:
Como foi apontado por vários comentaristas e geralmente é a melhor prática em todos os momentos, as variáveis devem ser citadas. Nesse caso, você deve e geralmente sempre deve citar suas variáveis.
No caso de
for i in ${usbs[@]}; do
,i
será definido para todas as palavras (separadas por espaços em branco) emusbs
. Se você citar comofor i in "${usbs[@]}"; do
, entãoi
será definido para cada elemento deusbs
, conforme desejado.Isso é principalmente um engano de novas linhas e variável bash, embora isso não cubra matrizes. A partir daí, para usar uma variável contendo várias linhas, você precisa dividir a expansão do parâmetro em nova linha e pular o globbing e, dependendo dos seus dados, possivelmente evitar outro desmembramento:
Para um array,
readarray/mapfile
como sugerido por Jesse_b é o mais simples, pois já divide em linhas. Mas você pode fazer isso 'manualmente' como acima:Sim, e seu código de atribuição estava correto:
Isso faz exatamente como necessário; em uma única variável (não uma matriz), ele armazena duas linhas
lsblk
separadas por uma nova linha. Mas umfor
loop não é a ferramenta certa para ler essa variável. Umwhile
loop é muito melhor, aqui está um exemplo com dados inventados, pois alguns leitores podem não ter nenhum dispositivo USB conectado:Resultado:
Aqui está um método ainda mais curto:
Nota: enquanto uma variável de estilo POSIX
x
simples não é um array,bash
permitex
ser identificada usando a notação de array e não reclamará porx
não ser um array. Demonstração:Resultado:
Mas
x
não é uma matriz. Se fosse, este código (usando o operador de atribuição debash
transformação de parâmetro ), definitivamente geraria uma matriz:A
...não:
Para contrastar, vamos comparar o acima com como seria se fosse um array. Primeiro faça um array bem parecido
y
e então use o operador ssignment para mostrar a diferença:A
Resultado: