Чому не використовується декілька команд із || або && умовна робота?


12

Це працює на оболонці (bash, dash):

[ -z "" ] && echo A || echo B
A

Однак я намагаюся написати сценарій оболонки POSIX , він починається так:

#!/bin/sh

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

readonly raw_input_string=${1}

[ -z "${raw_input_string}" ] && echo "The given argument is empty."; exit 1

І я не знаю чому, але я не отримую повідомлення :

Даний аргумент порожній.

якщо я називаю сценарій так:

./test_empty_argument ""

Чому так?


5
Див. Як я можу перевірити, чи змінна порожня або містить лише пробіли? способи тестування, якщо змінна порожня, не встановлена ​​чи містить лише пробіли. Питання в цьому питанні не має нічого спільного з цим.
ilkkachu

1
Просто використовуйтеif [ X”” = X”$var” ] ; then echo isempty ; fi
user2497

3
@ user2497 Немає підстав використовувати це в будь-якій оболонці, випущеній за останні 20 років. Це рішення для старих, баггі-черепашок.
чепнер

@chepner Отже, це невірне рішення? Щось ще треба використати?
user2497

6
[ "" = "$var" ]спрацювало б добре; порожній рядок, який цитується, не буде видалений зі списку аргументів [. Але це теж не потрібно, тому що [ -z "$var" ] також працює чудово.
чепнер

Відповіді:


37

Зауважте, що ваша лінія

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

це те саме, що

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."
exit 1

(без котирування ;, у більшості випадків, можна замінити символ нового рядка)

Це означає, що exit 1оператор завжди виконується незалежно від того, скільки аргументів було передано сценарію. Це в свою чергу означає, що повідомлення The given argument is empty.ніколи не матиме шансів на друк.

Щоб виконати більше одного оператора після тесту, використовуючи «синтаксис короткого замикання», згрупуйте оператори в { ...; }. Альтернативою є використання належного ifоператора (який, IMHO, виглядає більш чисто в сценарії):

if [ "$#" -ne 1 ]; then
    echo 'Invalid number of arguments, expected one.' >&2
    exit 1
fi

Ви маєте те саме питання, що і для вашого другого тесту.


Що стосується

[ -z "" ] && echo A || echo B

Це могло б працювати для даного прикладу, але загального

some-test && command1 || command2

б НЕ бути таким же , як

if some-test; then
    command1
else
    command2
fi

Натомість це більше схоже

if ! { some-test && command1; }; then
    command2
fi

або

if some-test && command1; then
    :
else
    command2
fi

Тобто, якщо або тест, або перша команда не вдається, друга команда виконує, що означає, що вона має потенціал для виконання всіх трьох задіяних операторів.


18

Це:

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

не:

[ "${#}" -eq 1 ] || { echo "Invalid number of arguments, expected one."; exit 1; }

Але замість цього:

{ [ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; } 
exit 1

Ваш сценарій виходить незалежно від того, скільки аргументів ви йому передали.


8

Один із способів зробити його більш зрозумілим - це визначити dieфункцію (à la perl) на зразок:

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

# then:

[ "$#" -eq 1 ] || die "Expected one argument, got $#"

[ -n "$1" ] || die "Empty argument not supported"

Ви можете додати більше дзвіночків, таких як кольори, префікс, номер рядка ... якщо потрібно.


На практиці ви коли-небудь називаєте свою dieфункцію кількома аргументами? (Якщо так, чи можете ви навести приклад?) Я використовую майже однакову dieфункцію, але використовую "$*"натомість, що може бути більше того, що ви маєте намір?
jrw32982 підтримує Моніку

3
Цінність "$@"полягає в тому, що вона дозволяє багаторядкові повідомлення без необхідності додавати буквальні нові рядки.
Чарльз Даффі

1
@ jrw32982, використовуючи "$*"для об'єднання аргументів з пробілами, це також означає, що вам потрібно встановити $IFSSPC, щоб він працював у всіх контекстах, включаючи те, де $IFSбуло змінено. Як альтернативи з ksh/ zsh, ви можете використовувати print -r -- "$@"або echo -E - "$@"в zsh.
Стефан Шазелас

@CharlesDuffy Так, але я ніколи не бачив цього робити в контексті dieфункції -type. Я запитую: на практиці ви коли-небудь бачили, щоб хтось писав die "unable to blah:" "some error", щоб отримати 2-рядкове повідомлення про помилку?
jrw32982 підтримує Моніку

@ StéphaneChazelas Добре. Так (у моїй постановці) так і має бути die() { IFS=" "; printf >&2 "%s\n" "$*"; exit 1; }. Ви коли-небудь особисто використовували цю dieфункцію, щоб printfстворити багато рядкове повідомлення про помилку, передавши кілька аргументів? Або ви коли-небудь передаєте один аргумент, щоб dieвін додав лише один новий рядок до результату?
jrw32982 підтримує Моніку

-1

Я часто бачив це як тест на порожню рядок:

if [ "x$foo" = "x" ]; then ...

Повинна бути "=" - виправлена.
wef

3
Ця практика буквально з 1970-х. Там немає ніяких підстав , щоб використовувати його з будь-якої оболонкою, яка відповідає стандарту ш 1992 POSIX (до тих пір , як правильне цитування використовується і тепер застаріле функціональність , такі як -a, -o, (і , )як derectives сказати , testщоб об'єднати кілька операцій в одному виклику уникайте ; див. маркери OB в pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html ).
Чарльз Даффі

Нелінуксні пристрої, що постачаються з оригінальним "ш", добре в 90-х - можливо, все одно. На моїй роботі в той час мені довелося писати переносні сценарії встановлення, і я використовував цю конструкцію. Я просто переглянув сценарії встановлення, які NVidia постачає для Linux, і вони все ще використовують цю конструкцію.
wef

NVidia може використовувати його, але це не означає, що вони мають якісь технічні обгрунтування для цього; На жаль, на жаль, поширеність розвитку культового культу в комерційному UNIX. Навіть у Heirloom Bourne немає жодної помилки - тому у кодової бази SunOS (що є останньою комерційною UNIX, яка надсилає не POSIX /bin/sh, а безпосередній попередник Heirloom Bourne) її також не було.
Чарльз Даффі

1
Я не ношу капелюха, тому не можу пообіцяти розмістити відео на YouTube, їсти його, якщо хтось виявить оболонку, опубліковану в комерційному UNIX із цією помилкою після 1990 року ... але якби я це зробив, це було б заманливо . :)
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.