Последствия безопасности упущения заключить переменную в кавычки в оболочках удара/POSIX

При использовании хинду источника и уже в хинду среде app-admin/eselect инструмент поможет Вам сделать это:

eselect kernel list

и

eselect kernel set

И если Вы не знакомы с установкой ядра genkernel, может быть очень полезным. Вы могли бы хотеть использовать - конфигурация = и - menuconfig, который не документируется в HandBook (HandBook является просто формой пошагового руководства перспектива некоторого dev, много инструментов, которые он упомянул, недооценены новыми читателями).

212
28.09.2017, 15:35
3 ответа

Преамбула

Во-первых, я бы сказал, что это неправильный способ решения проблемы. Это немного похоже на выражение " вы не должны убивать людей, потому что иначе вы попадете в тюрьму ».

Точно так же вы не заключаете переменную в кавычки, потому что в противном случае вы вносите уязвимости в системе безопасности. Вы цитируете переменные , потому что это неправильно (но если страх тюрьмы может помочь, почему бы и нет).

Небольшое резюме для тех, кто только что запрыгнул в поезд.

В большинстве оболочек, оставление раскрытия переменной без кавычек (хотя это (и остальная часть этого ответа) также применяется к подстановке команды ( `...` или $ (...) ) и арифметическое расширение ( $ ((...)) или $ [...] )) имеет очень особое значение .Лучше всего описать это как вызов некоторого неявного оператора split + glob .

cmd $var

на другом языке будет выглядеть примерно так:

cmd(glob(split($var)))

$ var сначала разбивается на список слов в соответствии со сложными правилами, включающими специальный параметр $ IFS ( часть split ) , а затем каждое слово, полученное в результате этого разделения, рассматривается как шаблон , который расширяется до списка файлов, соответствующих ему (часть glob ).

Например, если $ var содержит *. Txt, / var / *. Xml и $ IFS содержит ], , cmd будет вызываться с рядом аргументов, первый из них - cmd , а следующие - txt файлы в текущем каталоге и файлы xml в / var .

Если вы хотите вызвать cmd только с двумя буквальными аргументами cmd и *. Txt, / var / *. Xml , вы бы написали:

cmd "$var"

что было бы на другом вашем более знакомом языке:

cmd($var)

Что мы подразумеваем под уязвимостью в оболочке ?

В конце концов, это известно с незапамятных времен время, когда сценарии оболочки не должны использоваться в контекстах, чувствительных к безопасности. Конечно, хорошо, оставить переменную без кавычек - это ошибка, но она не может причинить столько вреда, не так ли?

Что ж, несмотря на то, что кто-нибудь скажет вам эту оболочку { {1}} скрипты никогда не должны использоваться для веб-CGI, или что, к счастью, в настоящее время большинство систем не позволяют использовать сценарии оболочки setuid / setgid, одна вещь, которая поражает оболочкой (удаленно эксплуатируемая ошибка bash { {1}}, который попал в заголовки в сентябре 2014 г.) показал, что оболочки по-прежнему широко используются там, где им, вероятно, не следует: в CGI, в сценариях подключения DHCP-клиента, в командах sudoers, вызывается командой (если не как ) командами setuid ...

Иногда неосознанно. Например, system ('cmd $ PATH_INFO') в php / perl / python скрипт CGI вызывает оболочку для интерпретации этой командной строки (не говоря уже о том, чтобы упомянуть тот факт, что cmd сам может быть сценарием оболочки, и его автор, возможно, никогда не ожидал, что он будет вызван из CGI).

У вас есть уязвимость, когда есть путь для повышения привилегий, то есть когда кто-то (назовем его злоумышленником ) может сделать то, что он не предназначено.

Неизменно это означает злоумышленник , предоставляющий данные, эти данные обрабатываются привилегированным пользователем / процессом, который непреднамеренно делает то, чего не должен делать, в большинстве случаев случаев из-за ошибки.

По сути, проблема возникает, когда ваш ошибочный код обрабатывает данные под контролем злоумышленника .

Теперь не всегда очевидно, откуда могут взяться эти данные , , и часто трудно сказать, сможет ли ваш код когда-либо обрабатывать ненадежные данные.

Что касается переменных. В случае сценария CGI, это совершенно очевидно, данные - это параметры CGI GET / POST и такие вещи, как файлы cookie, путь, хост. .. параметры.

Для сценария setuid (выполняющегося от имени одного пользователя, когда его вызывает другой) это аргументы или переменные среды.

Другой очень распространенный вектор - это имена файлов. Если вы получаете список файлов из каталога,возможно, файлы были помещены туда злоумышленником .

В этом отношении, даже при запросе интерактивной оболочки, вы можете быть уязвимы (при обработке файлов в / tmp или ~ / tmp {{ 1}}, например).

Даже ~ / .bashrc может быть уязвимым (например, bash интерпретирует его при вызове через ssh для запуска ForcedCommand как в git серверных развертываний с некоторыми переменными под управлением клиента ).

Теперь сценарий не может быть вызван напрямую для обработки ненадежных данных , но он может быть вызван другой командой, которая это делает. Или ваш неправильный код может быть скопирован в скрипты, которые это делают (вами через 3 года или одним из ваших коллег). Одно место, где это особенно критично , - это ответы на сайтах вопросов и ответов, поскольку вы никогда не узнаете, где могут оказаться копии вашего кода.

К делу; насколько это плохо?

Оставление переменной (или подстановки команды) без кавычек - это, безусловно, источник номер один уязвимостей безопасности, связанных с кодом оболочки. Отчасти потому, что эти ошибки часто приводят к уязвимостям , но также потому, что часто встречаются переменные без кавычек.

На самом деле, при поиске уязвимостей в коде оболочки первое, что нужно сделать, - это найти переменные без кавычек. Легко обнаружить, часто хороший кандидат, обычно легко отследить до данных, контролируемых злоумышленником.

Существует бесконечное количество способов, которыми переменная без кавычек может превратить в уязвимость. Я просто приведу здесь несколько общих тенденций.

Раскрытие информации

Большинство людей столкнутся с ошибками, связанными с переменными без кавычек из-за разделенной части (например, часто в файлах есть пробелы в их именах в настоящее время, а пробел находится в значении IFS по умолчанию). Многие люди упускают из виду часть glob . Часть glob по крайней мере так же опасна, как и разделенная часть .

Глобализация, выполняемая при необработанном внешнем вводе, означает злоумышленник может заставить вас прочитать содержимое любого каталога.

В:

echo You entered: $unsanitised_external_input

если $ unsanitised_external_input содержит / * , это означает, что злоумышленник может увидеть содержимое / . Ничего страшного. Это становится более интересным с помощью / home / * , который дает вам список имен пользователей на машине, / tmp / * , / home / * /. Forward для намеков на другие опасные действия, / etc / rc * / * для включенных служб ... Нет необходимости назвать их индивидуально. Значение / * / * / * / * / * / * ... просто перечислит всю файловую систему.

Уязвимости, связанные с отказом в обслуживании.

Если зайти слишком далеко в предыдущем случае, мы получили DoS-атаку.

Фактически, любая некотируемая переменная в контексте списка с неанитизированным входом является как минимум уязвимостью DoS.

Даже опытные разработчики сценариев оболочки обычно забывают цитировать такие вещи, как:

#! /bin/sh -
: ${QUERYSTRING=$1}

: - это команда, не выполняющая никаких действий.Что могло пойти не так?

Это означало присвоить $ 1 $ QUERYSTRING , если $ QUERYSTRING не задано. Это быстрый способ сделать сценарий CGI вызываемым из командной строки.

Этот $ QUERYSTRING все еще раскрывается, и поскольку он не цитируется, вызывается оператор split + glob .

Есть несколько глобусов, которые особенно дорого расширять . / * / * / * / * достаточно плох, так как он означает перечисление каталогов до 4 уровней ниже. Помимо активности диска и процессора , это означает сохранение десятков тысяч путей к файлам (40 КБ здесь на минимальной серверной ВМ, 10 КБ из которых - каталогов).

Теперь /*/*/*/*/../../../../*/*/*/* означает 40k x 10k и /*/*/*/*/../../../../*/*/*/*/../../../../*/*/*/* достаточно, чтобы поставить на колени даже самую мощную машину.

Попробуйте сами (хотя будьте готовы к тому, что ваша машина выйдет из строя или зависнет):

a='/*/*/*/*/../../../../*/*/*/*/../../../../*/*/*/*' sh -c ': ${a=foo}'

Конечно, если код:

echo $QUERYSTRING > /some/file

Тогда вы можете заполнить диск.

Просто выполните поиск в Google по оболочке cgi или bash cgi или ksh cgi , и вы найдете несколько страниц, на которых показано, как писать CGI в оболочках. Обратите внимание , насколько уязвима половина из тех, которые обрабатывают параметры.

Даже собственный файл Дэвида Корна уязвим (посмотрите на обработку файлов cookie).

вплоть до уязвимостей выполнения произвольного кода

Выполнение произвольного кода - наихудший тип уязвимости, поскольку, если злоумышленник может выполнить любую команду, нет ограничений на {{1} } что он может делать.

Обычно к ним приводит разделенная часть . Это разделение приводит к тому, что командам передается несколько аргументов, хотя ожидается только один. Хотя первый из них будет использоваться в ожидаемом контексте,другие будут в другом контексте , поэтому потенциально могут интерпретироваться по-разному. Лучше приведите пример:

awk -v foo=$external_input '$2 == foo'

Здесь целью было присвоить содержимое переменной оболочки $ external_input переменной foo awk .

Теперь:

$ external_input='x BEGIN{system("uname")}'
$ awk -v foo=$external_input '$2 == foo'
Linux

Второе слово, полученное в результате разделения $ external_input , не присваивается foo , но считается awk код (здесь выполняет произвольную команду: uname ).

Это особенно проблема для команд, которые могут выполнять другие команды ( awk , env , sed (один GNU), ] perl , find ...) особенно с вариантами GNU (которые принимают параметры после аргументов). Иногда вы не подозреваете, что команды может выполнять другие, например ksh , bash или zsh [ или printf ) ...

for file in *; do
  [ -f $file ] || continue
  something-that-would-be-dangerous-if-$file-were-a-directory
done

Если мы создадим каталог с именем x -o yes , тогда тест станет положительным, потому что это совершенно другое условное выражение , которое мы оцениваем .

Хуже того, если мы создадим файл с именем x -aa [0 $ (uname> & 2)] -gt 1 , по крайней мере со всеми реализациями ksh (включая sh большинства коммерческих Unix и некоторых BSD), который выполняет uname , потому что эти оболочки выполняют арифметические вычисления для операторов числового сравнения команда [.

$ touch x 'x -a a[0$(uname>&2)] -gt 1'
$ ksh -c 'for f in *; do [ -f $f ]; done'
Linux

То же самое с bash для имени файла, например x -a -v a [0 $ (uname> & 2)] .

Конечно, если они не могут добиться произвольного выполнения, злоумышленник может согласиться на меньший ущерб (что может помочь добиться произвольного выполнения). Любая команда, которая может записывать файлы или изменять разрешения, права собственности или иметь какой-либо основной или побочный эффект, может быть использована.

С именами файлов можно делать все, что угодно.

$ touch -- '-R ..'
$ for file in *; do [ -f "$file" ] && chmod +w $file; done

И в итоге вы делаете .. записываемым (рекурсивно с помощью GNU chmod ).

Скрипты, выполняющие автоматическую обработку файлов в общедоступных областях, таких как / tmp , должны быть написаны очень осторожно.

А как насчет [$ # -gt 1]

Меня это раздражает. Некоторые люди упускают все проблемы, задаваясь вопросом, может ли конкретное расширение быть проблематичным, чтобы решить, могут ли они опустить кавычки.

Это как сказать. Эй, похоже, что $ # не может подчиняться оператору split + glob, давайте попросим оболочку разделить + glob его . Или Эй, давайте напишем неверный код только потому, что ошибка вряд ли будет обнаружена .

Насколько это маловероятно? Хорошо, $ # (или $! , $? или любая арифметическая подстановка) может содержать только цифры (или - для некоторых), поэтому часть glob отсутствует. Однако для того, чтобы часть split что-то делала , все, что нам нужно, это чтобы $ IFS содержал цифры (или - ).

В некоторых оболочках $ IFS может быть унаследован от среды, но если среда небезопасна, игра все равно окончена.

Теперь, если вы напишете такую ​​функцию, как:

my_function() {
  [ $# -eq 2 ] || return
  ...
}

Это означает, что поведение вашей функции зависит от контекста, в котором она вызывается. Или, другими словами, $ IFS становится одним из его входов. Строго говоря, когда вы пишете документацию по API для своей функции, она должна быть примерно такой:

# my_function
#   inputs:
#     $1: source directory
#     $2: destination directory
#   $IFS: used to split $#, expected not to contain digits...

И код, вызывающий вашу функцию, должен убедиться, что $ IFS не 't не содержат цифр. Все потому, что вам не хотелось набирать эти два символа двойных кавычек.

Теперь, чтобы ошибка [$ # -eq 2] стала уязвимостью, вам нужно каким-то образом, чтобы значение $ IFS стало под контролем злоумышленника . Возможно, этого обычно не происходило бы , если бы злоумышленник не смог воспользоваться другой ошибкой.

Это не редкость. Распространенный случай - когда люди забывают очистить данные перед их использованием в арифметическом выражении . Мы уже видели выше, что он может разрешить выполнение произвольного кода в некоторых оболочках, но во всех из них он позволяет злоумышленнику присвоить любой переменной целочисленное значение. .

Например:

n=$(($1 + 1))
if [ $# -gt 2 ]; then
  echo >&2 "Too many arguments"
  exit 1
fi

И с $ 1 со значением (IFS = -1234567890) , эта арифметическая оценка имеет побочный эффект настроек IFS и следующая команда [ завершается ошибкой, что означает, что проверка на слишком большого количества аргументов пропущена.

Что делать, если оператор split + glob не вызывается?

Есть еще один случай, когда кавычки нужны вокруг переменных и других расширений: когда он используется в качестве шаблона.

[[ $a = $b ]]   # a `ksh` construct also supported by `bash`
case $a in ($b) ...; esac

не проверяет, совпадают ли $ a и $ b (кроме zsh )но если $ a соответствует шаблону в $ b . И вам нужно указать $ b , если вы хотите сравнивать как строки (то же самое в "$ {a # $ b}" или "$ {a% $ b}} " или " $ {a ## * $ b *} ", где $ b следует заключить в кавычки, если это не следует рассматривать как образец).

Это означает, что [[$ a = $ b]] может возвращать истину в тех случаях, когда $ a отличается от $ b (для например, когда $ a равно что-нибудь и $ b равно * ) или может возвращать false, когда они идентичны (например, когда оба $ a и $ b равны [a] ).

Может ли это привести к уязвимости системы безопасности? Да вроде любой баг. Здесь злоумышленник может изменить логический поток кода вашего скрипта и / или нарушить предположения, которые делает ваш скрипт. Например, с таким кодом:

if [[ $1 = $2 ]]; then
   echo >&2 '$1 and $2 cannot be the same or damage will incur'
   exit 1
fi

Злоумышленник может обойти проверку, передав '[a]' '[a]' .

Итак, если ни то сопоставление с образцом, ни оператор split + glob не применимы, в чем опасность оставить переменную без кавычек?

Я должен признать, что пишу:

a=$b
case $a in...

Там, цитирование не вредит, но не обязательно.

Однако одним из побочных эффектов опускания кавычек в этих случаях (например, в ответах на вопросы) является то, что это может послать неверное сообщение новичкам: что можно не заключать переменные в кавычки .

Например, они могут начать думать, что если a = $ b в порядке, то export a = $ b тоже будет (что не во многих shells в аргументах команды export в контексте списка) или env a = $ b .

А как насчет zsh ?

zsh исправил большинство этих неудобств дизайна. В zsh (по крайней мере, когда не в режиме эмуляции sh / ksh), если вы хотите разбиение , или подстановку , или сопоставление с образцом , вы должны запросить его явно: $ = var для разделения и $ ~ var для glob или для того, чтобы содержимое переменной обрабатывалось как шаблон.

Однако разделение (но не глобализация) все еще выполняется неявно при подстановке команд без кавычек (как в echo $ (cmd) ).

Кроме того, иногда нежелательным побочным эффектом отсутствия кавычек для переменной является удаление пустых . Поведение zsh аналогично тому, что вы можете достичь в других оболочках, полностью отключив подстановку (с помощью set -f ) и разделение (с помощью IFS = '' ) . Тем не менее, в:

cmd $var

Не будет split + glob , но если $ var пусто, вместо получения одного пустого аргумента cmd получит вообще никаких аргументов.

Это может вызвать ошибки (например, очевидный [-n $ var] ).Возможно, это может нарушить ожидания и предположения сценария и вызвать уязвимости, но я не могу сейчас привести не слишком надуманный пример).

Как насчет того, чтобы нужен оператор split + glob ?

Да, обычно вы хотите оставить переменную без кавычек. Но тогда вам нужно убедиться, что вы правильно настроили операторы split и glob , прежде чем использовать их. Если вам нужна только часть split , а не часть glob (что имеет место в большинстве случаев), то вам нужно отключить подстановку ( set -o noglob / set -f ) и исправьте $ IFS . В противном случае вы также вызовете уязвимости (например, пример CGI Дэвида Корна, упомянутый выше).

Заключение

Короче говоря, оставлять переменную (или подстановку команд или арифметическое раскрытие) без кавычек в оболочках может быть очень опасно действительно, особенно когда сделано в неправильном контексте, и это очень трудно понять, какие это неправильные контексты.

Это одна из причин, почему это считается плохой практикой .

Спасибо, что дочитали до сих пор. Если это пролетит над вашей головой, не волнуйтесь. Нельзя ожидать, что все поймут все последствия написания кода так, как они его пишут. Вот почему у нас есть рекомендаций по передовой практике , поэтому им можно следовать, не обязательно понимая почему.

(и в случае, если это еще не очевидно, избегайте написания кода, чувствительного к безопасности, в оболочках).

И , пожалуйста, укажите свои переменные в ответах на этом сайте!


¹В ksh93 и pdksh и производных, раскрытие фигурных скобок также выполняется, если подстановка не отключена (в случае версий ksh93 вплоть до ksh93u +, даже если опция braceexpand отключена).

207
27.01.2020, 19:28

Я скептически отнесся к ответу Стефана, однако можно злоупотребить $ # :

$ set `seq 101`

$ IFS=0

$ echo $#
1 1

или $ ?:

$ IFS=0

$ awk 'BEGIN {exit 101}'

$ echo $?
1 1

Это надуманные примеры, но потенциал есть.

11
27.01.2020, 19:28

[На основе этого ответа cas .]

Но что, если…?

Но что, если мой сценарий устанавливает для переменной известное значение перед ее использованием? В частности, что, если он устанавливает для переменной одно из двух или более возможных значений (но он всегда устанавливает для нее что-то известное), и ни одно из значений не содержит пробелов или символов глобуса? Разве не безопасно использовать его без кавычек в этом случае ?

А что, если одним из возможных значений является пустая строка, и я в зависимости от «удаления пустой тары»? То есть, если переменная содержит пустую строку, я не хочу получать пустую строку в моей команде; я не хочу ничего получать. Например,

if some_condition
then
    ignorecase="-i"
else
    ignorecase=""
fi
                                        # Note that the quotes in the above commands are not strictly needed.
grep  $ignorecase  other_grep_args

Я не могу сказать grep "$ ignorecase" other_ grep _args ; это не сработает, если $ ignorecase - пустая строка.

Ответ:

Как обсуждалось в другом ответе, это все равно не удастся, если IFS содержит - или i . Если вы убедились, что IFS не содержит никаких символов в вашей переменной (и вы уверены, что ваша переменная не содержит никаких глобальных символов), {{ 1}}, то это, вероятно, безопасно.

Но есть способ более безопасный (хотя он несколько уродлив и совершенно не интуитивен): используйте $ {ignorecase: + "$ ignorecase"} . Из спецификации языка команд оболочки POSIX , в 2.6.2 Расширение параметров ,

$ { параметр : + [ word ]}

    Использовать альтернативное значение. Если параметр не установлен или равен нулю, должен быть заменен ноль; в противном случае - раскрытие слова (или пустая строка, если слово опущено) заменяется.

Хитрость здесь, например, в том, что мы используем ignorecase как параметр и «$ ignorecase» как слово . Итак $ {ignorecase: + "$ ignorecase"} означает

Если $ ignorecase не задан или имеет значение null (т. Е. Пусто), null (т. е. без кавычек ничего ) должен быть заменен; в противном случае должно быть заменено расширение «$ ignorecase» .

Это приводит нас туда, куда мы хотим пойти: если для переменной задана пустая строка, она будет «удалена» (все это запутанное выражение будет вычислить ничего - даже не пустую строку), , и если переменная имеет непустое значение, мы получим это значение в кавычках.


Но что, если…?

Но что, если у меня есть переменная, которую я хочу / нужно разбить на слова? (В остальном это похоже на первый случай; мой сценарий установил переменную, , и я уверен, что она не содержит никаких глобальных символов. Но она может содержать пробел (s), и я хочу, чтобы он был разделен на отдельные аргументы на границах пространства.
PS Я все еще хочу удалить пустые места.)

Например,

if some_condition
then
    criteria="-type f"
else
    criteria=""
fi
if some_other_condition
then
    criteria="$criteria -mtime +42"
fi
find "$start_directory"  $criteria  other_find_args

Response:

Вы можете подумать, что это случай использования eval . Нет! Не поддавайтесь искушению даже подумать об использовании здесь eval .

Опять же, если вы убедились, что IFS не содержит ни одного символа в вашей переменной (кроме пробелов, которые вы хотите учитывать), и вы уверены, что ваша переменная не содержит каких-либо глобальных символов, тогда приведенное выше, вероятно, безопасно.

Но если вы используете bash (или ksh, zsh или yash), есть более безопасный способ: используйте массив:

if some_condition
then
    criteria=(-type f)  # You could say `criteria=("-type" "f")`, but it’s really unnecessary.
else
    criteria=()         # Do not use any quotes on this command!
fi
if some_other_condition
then
    criteria+=(-mtime +42)      # Note: not `=`, but `+=`, to add (append) to an array.
fi
find "$start_directory"  "${criteria[@]}"  other_find_args

From bash (1) ,

На любой элемент массива можно ссылаться , используя $ { name [ индекс ]} .… Если подстрочный индекс равен @ или * , слово расширяется до всех членов name . Эти индексы различаются только в том случае, если слово заключено в двойные кавычки. Если слово заключено в двойные кавычки,… $ { name [@]} заменяет каждый элемент name на отдельное слово.

Итак "$ {критерии [@]}" заменяется (в приведенном выше примере) нулем, двумя или четырьмя элементами массива критериев . , каждый процитирован. В частности, если ни одно из условия s не выполняется, массив критериев не имеет содержимого (как установлено критериев = () оператор), и "$ {критерии [@]}" не оцениваются как ничего (не даже неудобная пустая строка).


Это становится особенно интересным и сложным , когда вы имеете дело с несколькими словами, некоторые из которых являются динамическим (пользовательским) вводом, о котором вы не знаете заранее, {{1} } и может содержать пробелы или другие специальные символы. Учтите:

printf "Enter file name to look for: "
read fname
if [ "$fname" != "" ]
then
    criteria+=(-name "$fname")
fi

Обратите внимание, что $ fname цитируется каждый раз, когда используется. Это работает, даже если пользователь вводит что-то вроде foo bar или foo * ; "$ {критерии [@]}" оцениваются как -имя "foo bar" или -имя "foo *" . (Помните, что каждый элемент массива заключен в кавычки.)

Массивы работают не во всех оболочках POSIX; массивы - это ksh / bash / zsh / yash-ism. Кроме… есть один массив, который поддерживают все оболочки: список аргументов, он же «$ @» . Если вы закончили со списком аргументов, с которым вы были вызваны (например, вы скопировали все «позиционные параметры» (аргументы) в переменные, или обработали иным образом их), вы можете использовать список аргументов как массив:

if some_condition
then
    set -- -type f      # You could say `set -- "-type" "f"`, but it’s really unnecessary.
else
    set --
fi
if some_other_condition
then
    set -- "$@" -mtime +42
fi
# Similarly:    set -- "$@" -name "$fname"
find "$start_directory"  "$@"  other_find_args

Конструкция "$ @" (которая исторически появлялась первой) имеет ту же семантику, что и " $ { name [@]} " - расширяет каждый аргумент (т. Е. Каждый элемент списка аргументов) до отдельного слова, как если бы вы набрал «$ 1» «$ 2» «$ 3»… .

Выдержка из спецификации языка команд оболочки POSIX , в разделе 2.5.2 Специальные параметры ,

@

    Расширяется до позиционных параметров, начиная с от одного, первоначально создает одно поле для каждого установленного позиционного параметра. …, исходные поля должны быть сохранены как отдельные поля,…. Если нет позиционных параметров, расширение @ должно генерировать нулевые поля, даже если @ находится в пределах двойного цитаты; …

Полный текст несколько загадочен; ключевым моментом является то, что он указывает , что "$ @" будет генерировать нулевые поля , когда есть не являются позиционными параметрами. Историческое примечание: когда "$ @" впервые был представлен в оболочке Bourne (предшественник bash) в 1979 году, в нем была ошибка, "$ @" было заменено одной пустой строкой , когда не было позиционных параметров; см. Что означает $ {1 + "$ @" } означает в сценарии оболочки и чем он отличается от «$ @» ? , Традиционное семейство оболочки Борна , Что означает $ {1 + "$ @"} ... и где это необходимо? , и "$ @" против $ {1 + "$ @"} .


Массивы помогают и в первой ситуации:

if some_condition
then
    ignorecase=(-i)     # You could say `ignorecase=("-i")`, but it’s really unnecessary.
else
    ignorecase=()       # Do not use any quotes on this command!
fi
grep  "${ignorecase[@]}"  other_grep_args

____________________

P.S. (csh)

Это должно быть само собой разумеющимся, но для удобства новичков: csh, tcsh и т. д. не являются оболочками Bourne / POSIX. Это совсем другая семья. Лошадь другого цвета. Совершенно другая игра с мячом. Кошка другой породы. Птицы другого пера. И, в частности, другая банка с червями.

Кое-что из того, что было сказано на этой странице, относится к csh; например: рекомендуется заключать в кавычки все переменные , если у вас нет веской причины не делать этого, {{1} } и вы уверены, что знаете, что делаете. Но в csh каждая переменная является массивом - так уж получилось, что почти каждая переменная является массивом только из одного элемента и действует примерно одинаково {{1} } в обычную переменную оболочки в оболочках Bourne / POSIX. И синтаксис ужасно другой (я имею в виду ужасно ). Поэтому мы не будем здесь больше ничего говорить об оболочках семейства csh.

34
27.01.2020, 19:28

Теги

Похожие вопросы