Как использовать переменную среды внутри строки в кавычках в Bash

95

Я пробовал различные формы следующего в сценарии bash:

#!/bin/bash
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Но я не могу заставить синтаксис правильно расширять COLUMNSпеременную среды.

Я пробовал различные формы следующего:

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W $COLUMNS'

а также

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W ${COLUMNS}'

а также

eval svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Предложения?

Джейми
источник
Итак, что эти примеры производят в вашем случае? И что вы хотите, чтобы они производили?
команда вне скрипта работает?
dfa
Вы пробовали?svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Цянь Чен
Кстати, использование без $@кавычек делает его точно таким же, как $*- то есть, он разбивается "foo bar"на два отдельных аргумента, fooи bar. Если вы хотите сохранить исходный список аргументов в том виде, в каком он был вам предоставлен, вы этого хотите "$@".
Чарльз Даффи

Ответы:

16

Если вы не уверены, вы можете использовать запрос cols на терминале и забыть COLUMNS:

COLS=$(tput cols)
Бонсай
источник
По какой-то причине это единственное решение, которое мне удалось отработать на этой странице (по состоянию на 11 мая, 10:38 по восточному времени). Спасибо
Джейми
407

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

echo "$VARIABLE"
echo "${VARIABLE}"

Использование одинарных кавычек - основная проблема. Согласно справочному руководству Bash :

Заключение символов в одинарные кавычки ( ') сохраняет буквальное значение каждого символа внутри кавычек. Одинарные кавычки не могут находиться между одинарными кавычками, даже если им предшествует обратная косая черта. [...] Ограждающие символы в двойных кавычках ( ") сохраняет буквальное значение всех символов в кавычках, за исключением $, `, \и, когда раскрывание истории включено, !. Символы $и `сохраняют свое особое значение в двойных кавычках (см. Расширения оболочки). Обратный слэш сохраняет свой особый смысл только тогда , когда следует один из следующих символов: $, `, ",\, или перевод строки. В двойных кавычках удаляются обратные косые черты, за которыми следует один из этих символов. Обратные косые черты перед символами без специального значения остаются неизменными. Двойные кавычки можно заключить в двойные кавычки, поставив перед ними обратную косую черту. Если этот параметр включен, раскрытие истории будет выполняться, если только !появление в двойных кавычках не будет экранировано с помощью обратной косой черты. Обратная косая черта перед символом !не удаляется. Специальные параметры *и @имеют особое значение в двойных кавычках (см. Расширение параметров оболочки).

В конкретном случае, заданном в вопросе, $ COLUMNS - это специальная переменная, которая имеет нестандартные свойства (см. Ответ lhunath выше).

Рекурсивно
источник
20
В случае одинарных кавычек, возможно, этот обходной путь поможет: 'before'"$variable"'after'(как указано в этом ответе: stackoverflow.com/a/13802438/2254346 )
MakisH
Отличный ответ! У меня была такая же проблема со ссылкой на мою переменную env в одинарных кавычках. Как только я изменил одинарные кавычки на двойные, моя переменная env расширилась, как и ожидалось.
Binita Bharati
14

Обратите внимание, что COLUMNSэто:

  1. НЕ переменная среды. Это обычный параметр bash, который устанавливается самим bash.
  2. Устанавливается автоматически при получении SIGWINCHсигнала.

Этот второй пункт обычно означает, что ваша COLUMNSпеременная будет установлена ​​только в вашей интерактивной оболочке, а не в сценарии bash.

Если ваш скрипт stdinподключен к вашему терминалу, вы можете вручную посмотреть ширину вашего терминала, спросив свой терминал:

tput cols

И чтобы использовать это в своей команде SVN:

svn diff "$@" --diff-cmd /usr/bin/diff -x "-y -w -p -W $(tput cols)"

(Примечание: вы должны цитировать "$@" и держаться подальше eval;-))

лхунатх
источник
Спасибо за информацию; знание того, что происходит, привносит в проблему ощущение катарсиса.
Джейми
2

Следующий сценарий работает для меня для нескольких значений $COLUMNS. Интересно, не настраиваете ли вы COLUMNSдо этого звонка?

#!/bin/bash
COLUMNS=30
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Можете ли вы повторить эхо $COLUMNSв своем скрипте, чтобы увидеть, правильно ли он настроен?

Алекс Б
источник
Бу, шипение re: unquoted $@- разделяет один параметр "two words"на два отдельных параметра twoи words. Должен быть "$@"передан список аргументов в точности так, как он был задан.
Чарльз Даффи
0

Вы делаете это правильно, поэтому я предполагаю, что виновата что-то еще (не экспорт COLUMNS?).

Уловка для отладки этих случаев состоит в том, чтобы создать специализированную команду (закрытие для тех, кто занимается языком программирования). Создайте сценарий оболочки с именем diff-columns, выполняя:

exec /usr/bin/diff -x -y -w -p -W "$COLUMNS" "$@"

и просто используйте

svn diff "$@" --diff-cmd  diff-columns

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

Колас Нахабу
источник
Командная строка анализируется перед тем, как процесс будет разветвлен, поэтому отсутствие экспорта COLUMNS не может быть проблемой.
Питер ван дер Хейден,
1
Он говорит свой код как часть сценария bash, поэтому это может быть проблемой.
Колас Нахабу,