Obtendo nenhuma saída de substituição de comando?

0

Eu escrevi alguns scripts de shell, mas nunca vi esse comportamento e estou perdido. Eu tenho o seguinte script simples que é executado em um shell bash:

LOGFILE="/var/log/constructor-events.txt"

SUBSYSTEM="$1"
DEVTYPE="$2"
DEVICE="$3"

VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)

REQUEST=$(cat <<EOF
{"data": {
    "action": "add",
    "port": {
        "type": "$SUBSYSTEM",
    },
    "drive": {
        "vendor_id": "$VENDOR",
    }
}}
EOF
)

printf "output: $VENDOR" >> $LOGFILE
printf "%s\n" "'date +%x\ %r\ %Z' $REQUEST"  >> $LOGFILE

Isso é executado a partir de uma regra do udev. Os parâmetros posicionais (provenientes do udev) têm os valores esperados e não tenho nenhum problema em imprimi-los no arquivo de log. Mas, por algum motivo, a variável $VENDOR não contém saída do comando lsusb .

Aqui está a depuração que fiz.

  • Adicionado o redirecionamento stderr ao stdout para capturar qualquer erro que possa ser ocorrendo.
  • Adicionada a linha para enviar a variável $VENDOR diretamente para o log, que está vazio.
  • Executou o script manualmente no shell e imprimiu a variável $VENDOR no terminal e está vazia.
  • Tomou a string contida na variável $DEVICE e executou diretamente no shell, com este resultado.

    [root@host ~]# lsusb -D /dev/bus/usb/016/030 | grep idVendor
    Cannot open /dev/bus/usb/016/030
    

Por que a variável $VENDOR está vazia ao enviar para o arquivo de log?

EDITAR:

Aqui está uma atualização depois de remover o redirecionamento da substituição de comando.

  • Adicionada uma linha para imprimir a variável $VENDOR no terminal.
  • Estaticamente atribuído o valor em vez de usar a variável $DEVICE .

Imprimir $VENDOR no terminal gera o erro, mas ele ainda não foi anexado ao arquivo de log! O valor de $DEVICE IS no arquivo de log. Acredito que tenha algo a ver com o redirecionamento de saída dentro da substituição de comandos.

    
por EternalHour 21.12.2017 / 05:49

1 resposta

3

Aqui, se lsusb der um erro, a mensagem de erro não será redirecionada, apenas erros de grep . Os erros de lsusb continuam a ser os usuais stderr , ou seja, o terminal (ou o que quer que seja stderr quando o script foi iniciado.

VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)

Por exemplo,

$ blah=$(ls -l /nonexisting | grep foo 2>&1)
ls: cannot access '/nonexisting': No such file or directory
$ echo "blah: '$blah'"
blah: ''

Você precisará redirecionar ambas as saídas como um grupo para que a substituição do comando capture o erro também:

$ blah=$( { ls -l /nonexisting | grep foo; } 2>&1)
$ echo "blah: '$blah'"
blah: 'ls: cannot access '/nonexisting': No such file or directory'

Usar redirecionamentos separados como $( foo 2>&1 | grep 2>&1 ) enviaria os erros do primeiro comando para o pipe e para grep para filtrar, o que no exemplo acima produziria novamente uma saída vazia.

    
por 21.12.2017 / 07:04