Нужны ли кавычки для присваивания локальной переменной?

36

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

function foo {
    local myvar=${bar}
    stuff()
}

Я в основном заинтересован bash, но любая информация о угловых коробках в других оболочках приветствуется.

rahmu
источник
Я думаю, что нет никакой разницы, если он находится в одной строке, как у вас это в вашей функции. Задания не нуждаются в цитировании. См. Mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

Ответы:

41

Котировки необходимы export foo="$var"или local foo="$var"(или readonly, typeset, declareи другие переменные объявлении команд ) в:

  • dash
  • shиз NetBSD (также на основе Almquist оболочки).
  • shИз FreeBSD 9.2 или старше (см изменений в 9.3 )
  • yash
  • zshс версиями до 5.1 in kshили shэмуляцией (или для того, export var="$(cmd)"где zshиначе можно было бы разделить слова (не используя globbing)).

В противном случае расширение переменной будет подвержено разделению слов и / или генерации имени файла, как в любом аргументе любой другой команды.

И не нужны в:

  • bash
  • ksh (все реализации)
  • shиз FreeBSD 9.3 или более поздней версии
  • busybox 'на основе пепла sh(с 2005 года)
  • zsh

В zsh, split + glob никогда не выполняется при расширении параметра, если только в shили kshэмуляция, но split (не glob) выполняется при замене команды. Начиная с версии 5.1, export/ localи другие команды объявления стали командами с двумя ключевыми словами / встроенными, как в других оболочках выше, что означает, что в кавычках нет необходимости, даже в sh/ kshemulation и даже для подстановки команд.

Существуют особые случаи, когда цитирование необходимо даже в этих оболочках, например:

a="b=some value"
export "$a"

Или, в более общем смысле, если что-либо, оставленное =(включая =), заключено в кавычки или является результатом какого-либо расширения (например export 'foo'="$var", export foo\="$var"или export foo$((n+=1))="$var"(это $((...))также должно быть указано в действительности) ...). Или другими словами, когда аргументexport не будет допустимым присваиванием переменной, если написано без export.

Если export/ localимя команды сам котируются (даже в части , как "export" a="$b", 'ex'port a="$b", \export a="$b"или даже ""export a="$b"), кавычки вокруг $bнужны только в AT & T kshиmksh .

Если export/ localили какая-то его часть является результатом некоторого расширения (например, в cmd=export; "$cmd" a="$b"или дажеexport$(:) a="$b" ) или в подобных вещах dryrun=; $dryrun export a="$b"), то кавычки необходимы в каждой оболочке.

В случае > /dev/null export a="$b" , кавычки необходимы pdkshи некоторые из его производных.

Для command export a="$b", кавычки необходимы в каждой оболочке, но mkshи ksh93(с теми же оговорками о commandиexport не является результатом некоторого расширения).

Они не нужны в любой оболочке, когда написано:

foo=$var export foo

(этот синтаксис также совместим с оболочкой Bourne, но в последних версиях zshработает только в sh/ksh emulation).

(Обратите внимание, что var=value local var не следует использовать, так как поведение зависит от оболочки).

Также обратите внимание, что использование exportс присваиванием также означает, что статус выхода cmdin export var="$(cmd)"потерян. Делать это какexport var; var=$(cmd) будто нет этой проблемы.

Также остерегайтесь этого особого случая с bash:

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
ab
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b

Я бы посоветовал всегда цитировать.

Стефан Шазелас
источник
3
Обратите внимание , что в zshкавычках будут необходимы для local foo="$(cmd)"потому wordsplitting (но не имя файла поколение) будет выполняться для некотируемой подстановки команд (но не для некотируемых расширений параметров), если KSH_TYPESETне включено, и в этом случае кавычка не нужна. Есть смысл? Нет? Тогда всегда цитируйте все, если вы точно не знаете, что делаете.
Мэтт
2
@Matt, мне нравится твой вывод. : D Забавно, большая часть того, что я узнал о сценариях оболочки, была получена из этого стекового обмена, так что я не осознавал, что всегда заключать в кавычки ваши переменные не является общеизвестным среди авторов сценариев. Я обнаружил, что у меня есть много задач по созданию существующих производственных сценариев, написанных людьми, которые не цитировали и не знали точно, что они делают ...
Wildcard
3

Я обычно цитирую любое использование переменных, где могут быть такие символы, как пробелы. В противном случае вы столкнетесь с такими проблемами:

#!/bin/bash

bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"
}

foo

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

  printf "%s\n" "$myvar"

ПРИМЕЧАНИЕ. Помните, что именно эта переменная $IFSопределяет символы разделителя.

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.

пример

С включенной отладкой в ​​Bash мы можем видеть, что происходит за кулисами.

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
hi
bye
+ printf '%s\n' 'hi bye'
hi bye

В приведенном выше примере мы видим, что переменная $barбыла передана нормально, $myvarно затем, когда мы перешли на использование, $myvarмы должны были знать содержание того, $myvarкогда мы ее использовали.

SLM
источник
2
Слово расщепления не единственная проблема , с некотируемым переменными, вы должны рассмотреть поколение файла (он же подстановка) , а также (хотя это (оба) не применяется в назначении переменных и bashи kshв local/ typeset... Специальные модули).
Стефан Шазелас