Тестування, чи змінна порожня в сценарії оболонки


27

Я бачив таку методику, яку багато разів використовували на різних оболонках, щоб перевірити, чи змінна порожня:

if [ "x$1" = "x" ]; then 
    # Variable is empty
fi

Чи є якісь переваги щодо використання цього над більш канонічним if [ -z "$1" ]? Чи може це бути проблемою переносимості?

Відповіді:


17

Деякі історичні оболонки реалізували дуже простий аналізатор, який може заплутатися в таких речах, як, наприклад, [ -n = "" ]перший операнд, =схожий на оператора, і розбере це як [ -n = ]або викликає синтаксичну помилку. В результаті [ "x$1" = x"" ], xпрефікс гарантує, що він x"$1"не може бути схожим на оператора, і тому єдиний спосіб оболонки проаналізувати цей тест - це трактуватись =як двійковий оператор.

Усі сучасні оболонки, і навіть більшість старих снарядів, які все ще працюють, дотримуються правил POSIX, які передбачають, що всі тестові вирази розміром до 4 слів будуть правильно розібрані. Це [ -z "$1" ]правильний спосіб тестування, якщо $1він порожній , і [ "$x" = "$y" ]це правильний спосіб перевірити рівність двох змінних.

Навіть деякі поточні оболонки можуть плутатись із більш тривалими виразами, а декілька виразів насправді неоднозначні, тому уникайте використання операторів -aта -oдля побудови довших булевих тестів, а замість цього використовуйте окремі виклики [та власні &&та ||булеві оператори оболонки .


3
Це не лише історичні оболонки. Деякі проблеми ksh88, що базуються shна деяких комерційних Unice, все ще мають проблему. Детальніше дивіться тут .
Стефан Шазелас

Це твердження невірне: [ -z "$1" ]це правильний спосіб тестування, якщо $1він порожній . sh -c '[ -z "$1" ]' ''; sh -c '[ -z "$1" ]'- обидва повертають 0, але у другому випадку $1не може бути порожнім, оскільки його немає.
mikeserv


3

Вищеописані тести також спричинить помилку, якщо ви працюєте з "set -u" або "set -o nounset"

Більш стабільним способом перевірити порожню змінну буде використання розширення параметрів :

MYVAR = $ {MYVAR: - "Погане значення"}

Цей метод працює для традиційної оболонки бурна, а також ksh і bash.


2
Я вважаю, що це написано як -> M = $ {M: - "Погана вартість"}
Gyan

0
    function isBlank {
 valueNoSpaces=$(echo "$@" | tr -d ' ')

 if [  "$valueNoSpaces" == null ] || [ -z "$valueNoSpaces" ] 
 then
       echo true ;
 else
       echo ""  ;
 fi
}

#Test
if [ $(isBlank "      ") ] 
then
    echo "isBlank \"      \" : it's blank"
else
    echo " isBlank \"      \": it is not blank"
fi

if [ $(isBlank "abc") ] 

then
    echo "isBlank \"abc\" : it's blank"
else
    echo "isBlank \"abc\" :it is not blank"
fi

if [ $(isBlank null) ] 
then
      echo "isBlank null : it's blank"
else
    echo "isBlank null : it is not blank"
fi

if [ $(isBlank "") ] 
then
    echo "isBlank \"\" : it's blank"
else
    echo "isBlank \"\" : it is not blank"
fi

#Result
isBlank "      " : it's blank

isBlank "abc" :it is not blank

isBlank null : it's blank

isBlank "" : it's blank

3
Привіт! Я не впевнений, як це дає відповідь на питання, яке запитує, чому використовувати =проти -z, а тепер як.
dhag
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.