Bash lança erro, linha 8: $ 1: variável não acoplada

14

Estou tentando aprender como usar getopts para que eu possa ter scripts com entrada analisada (embora eu ache que as getopts poderiam ser melhores). Estou tentando apenas escrever um script simples para retornar porcentagens de uso da partição. O problema é que uma das minhas funções do bash não parece gostar da referência $1como uma variável dentro da função. A razão de eu referenciar $1é porque a get_percentfunção pode receber um ponto de montagem como um argumento opcional a ser exibido em vez de todos os pontos de montagem.

O script

#!/usr/bin/bash

set -e
set -u
set -o pipefail

get_percent(){
    if [ -n "$1" ] 
    then
        df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
    else
        df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
    fi
}

usage(){
    echo "script usage: $(basename $0) [-h] [-p] [-m mount_point]" >&2
}

# If the user doesn't supply any arguments, we run the script as normal
if [ $# -eq 0 ];
then
    get_percent
    exit 0
fi
# ...

A saída

$ bash thing.sh
thing.sh: line 8: $1: unbound variable

$ bash -x thing.sh
+ set -e
+ set -u
+ set -o pipefail
+ '[' 0 -eq 0 ']'
+ get_percent
thing.sh: line 8: $1: unbound variable
Timothy Pulliam
fonte
Eu não acho que isso tenha algo a ver getopts, não é? Seu script é encerrado -uantes de ligar getopts.
Ilkkachu
@ikkachu não, acho que não. Mas não tenho certeza se posso mudar o título agora.
Timothy Pulliam
Não deve ser tão pequeno texto "Editar" sob o post, logo abaixo as tags em uma pergunta
ilkkachu

Respostas:

29

set -userá cancelado exatamente como você descreve se fizer referência a uma variável que não foi definida. Você está invocando seu script sem argumentos, portanto, get_percentestá sendo invocado sem argumentos, fazendo $1com que seja desabilitado.

Verifique isso antes de chamar sua função ou use expansões padrão ( ${1-default}será expandido para defaultse ainda não estiver definido para outra coisa).

DopeGhoti
fonte
Eu suspeitava disso, mas não conseguia pensar em uma maneira de contornar isso. A expansão padrão parece ter corrigido. Muito obrigado!
Timothy Pulliam
7
Em particular, pode-se usar [ -n "${1-}" ](ou seja, com um valor padrão vazio) para verificar se o parâmetro está definido e não vazio; ou [ "${1+x}" = x ]para ver se está definido, mesmo que vazio.
Ilkkachu
Eu ainda recebo erro variável ilimitado, apesar de usarif [[ -n ${1-default} ]]
Chaitanya Bapat
6

Este é o efeito de set -u.

Você pode verificar $#dentro da função e evitar referências $1se não estiver definido.

Com $#você pode acessar o número de parâmetros. No contexto global, é o número de parâmetros para o script, em uma função é o número de parâmetros para a função.

No contexto da questão, é

if [ $# -ge 1 ] && [ -n "$1" ]
then
    df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
else
    df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
fi

Observe que você precisa usar [ $# -ge 1 ] && [ -n "$1" ]e não [ $# -ge 1 -a -n "$1" ], porque isso primeiro avaliaria $1e depois verificava $#.

RalfFriedl
fonte
Você pode explicar mais como usar $ # e como verificá-lo? Obrigado
Chaitanya Bapat 07/12/19
1
Eu adicionei um exemplo.
RalfFriedl
3

Como é bashpossível contornar a verificação para $1definir e usar "$@"( $1é o primeiro parâmetro, $@são todos eles; quando aspas duplas, desaparece completamente se não tiver valores, o que evita que ela seja capturada set -u):

get_percent() {
    df -h "$@" | awk 'NR>1 { printf "%s\t%s\n", $1, $5 }'
}

Também ajustei o restante da linha levemente para que você não tenha {space} {tab} {space} entre os dois valores que você produz, mas insira que você tenha apenas uma {tab}. Se você realmente deseja os dois espaços invisíveis, altere awkpara usar printf "%s \t %s\n", $1, $5.

roaima
fonte
Vou ter que olhar para isso. Não estou familiarizado com esse tipo de variável. Graças
Timothy Pulliam
@TimothyPulliam Adicionei uma breve explicação $@sobre você
roaima 7/19/19