Чому [-n] не відповідає false як [-n “”]?


20

Моє запитання щодо зворотних значень, отриманих цим кодом:

if [ -n ]; then echo "true"; else echo "false"; fi

Це відбитки true.

Його додатковий тест з використанням [ -z ]також друкує true:

if [ -z ]; then echo "true"; else  echo "false"; fi

У наведеному вище коді чому [ -n ]тест припускає значення рядка, яке взагалі не передається, як недійсне?

Код нижче друкується false. Це очікується, оскільки значення переданого рядка є нульовим і дорівнює нулю.

if [ -n "" ]; then echo "true"; else  echo "false"; fi

Відповіді:


14

[x] еквівалентний [ -nx,] навіть якщо x починається з -того, що немає операнду.

$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0

4
Зауважимо, що історично [ -t ]перевіряли, чи stdout є терміналом (короткий для [ -t 1 ]), і деякі оболонки все ще роблять це (у випадку ksh93лише тоді, коли -tце буквально), тому краще використовувати [ -n "$var" ]ніж [ "$var" ]. Хоча це все одно не в деяких старих testреалізаціях для значень , $varяк =, в цьому випадку , [ "" != "$var" ]або [ "x$var" != x ]чи case $x in "")...може бути краще.
Стефан Шазелас

3
Цікавий вибір -oтут. У деяких оболонках, як bash, наприклад , -oє унарний (тест, якщо параметр встановлений) та бінарний (або) оператор, тому речі на зразок [ ! -o monitor ]неоднозначні. Чи перевіряється те, що monitorпараметр не встановлений, або що є !чи monitorне порожніми рядками? Правила POSIX вирішують: останні (що відрізняється від [[ ! -o monitor ]]).
Стефан Шазелас

30

[ -n ]не використовує -nтест.

-nУ [ -n ]це не тест на всіх. Якщо між [і є лише один аргумент ], цей аргумент - це рядок, який тестується, щоб перевірити, чи він порожній. Навіть коли ця струна має провідне місце -, вона все ж інтерпретується як операнд, а не тест. Оскільки рядок -nне порожній - він містить два символи -і n, не нульові символи, - [ -n ]оцінює як істинне.

Як каже Ігнасіо Васкес-Абрамс , де stringє єдиний аргумент, тест, виконаний stringв, є таким же, як і тест, виконаний ним . Коли буває , нічого особливого не відбувається. В і друге в просто рядки, яку відчувають порожнечу.[ string ][ -n string ]string-n-n[ -n ]-n[ -n -n ]

Якщо між [і ]аргументом є лише один аргумент , цей аргумент - це завжди рядок, який слід перевірити на непомітність, навіть якщо він має бути названий таким же, як тест. Точно так само, коли між [та ]і першим з них є два аргументи -n, другий - це завжди рядок, який підлягає тестуванню на непомітність, навіть якщо він трапляється називатися таким же, як і тест. Це просто тому, що синтаксис для [наполягає на тому, що один аргумент між [і ]після -n- це рядковий операнд.

З тієї ж причини, [ -n ]яка не використовує -nтест, [ -z ]не використовує -zтест.


Ви можете дізнатися більше про [в bash, досліджуючи допомогу для нього. Зауважте, що це вбудована оболонка :

$ type [
[ is a shell builtin

Таким чином, ви можете запустити, help [щоб отримати допомогу в цьому:

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

Для отримання додаткової інформації, зокрема про те, які тести підтримуються та як вони працюють, вам доведеться переглянути довідку test. Після запуску команди help testви отримаєте детальний список. Замість того, щоб відтворити все це, ось частина про рядкові оператори:

      -z STRING      True if string is empty.

      -n STRING
         STRING      True if string is not empty.

      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

Зауважте це, -n STRINGі просто STRINGзробіть те саме: вони перевіряють, чи рядок STRINGне порожній.


2
Гарне пояснення
Сергій Колодяжний

1
Можливо також зауважте, що це має значення для нецитованих
Сергій Колодяжний

1
@SergiyKolodyazhnyy Я думаю, що це може бути краще в окремій відповіді. Змінні, які не встановлені, або встановлені, але порожні, або містять лише IFSпробіли, зроблять це; змінні, що містять кілька слів замість нуля, дають інший ефект і можуть спричинити запуск зовсім іншого тесту. Рядки, які відображаються буквально з наміром бути операндами, працюватимуть належним чином лише у тому випадку, якщо вони не містять пробілів чи вкладок або якщо вони цитуються. Відповідь стала б набагато довшою та складнішою, якби я висвітлював цю тему доступним чином. Якщо ви вирішили опублікувати відповідь, не соромтесь @ mі тут про це!
Елія Каган

@Eliah Kagan, ваша відповідь є більш повною і детальною, хоча відповідь Ігнасіо Васкеса-Абрамса відповіла на моє запитання.
Раві Кумар

1
Я думаю, що ти пропускаєш причину, якою вона є, і має бути саме так: як ні, [ "$var" ]ніколи не була б корисною як тест, тому що $varможе розширитися до -n.
Р ..

12

[ -n ]вірно, тому що [команда (також testкоманда) діє на кількість заданих аргументів. Якщо йому надається лише один аргумент, результат є "true", якщо аргумент є не порожнім рядком. "-n" - рядок з 2 символами, не порожній, тому "true".

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