Допустим, я хочу сохранить следующую команду в переменной
cd "/cygdrive/c/Program Files/"
Так что я делаю это
dir="cd \"/cygdrive/c/Program Files/\""
В ней должна храниться команда для перехода в каталог Program Files, поэтому, когда я набираю $ dir, он переносит меня в этот каталог. Чтобы проверить, что цитаты были правильно экранированы, я набираю
echo $dir
что дает мне
cd "/cygdrive/c/Program Files/"
Так что все должно работать нормально. Тем не менее, когда я печатаю,
$dir
я получил
bash: cd: "/cygdrive/c/Program: No such file or directory
Что я делаю неправильно? Я использую Cygwin, но я предполагаю, что эта проблема относится к Bash в целом.
Ответы:
Краткий ответ: см. BashFAQ # 050 («Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу!»).
Длинный ответ: когда bash анализирует команду, он анализирует кавычки перед тем, как заменить переменные; он никогда не возвращается и повторно анализирует кавычки в значениях переменных, поэтому они в итоге не делают ничего полезного. Использование echo для проверки команды полностью вводит в заблуждение, поскольку она показывает команду после ее анализа; если вы хотите увидеть, что в действительности выполняется, используйте либо
set -x
команды печати оболочки по мере их выполнения, либо используйтеprintf "%q " $dir; echo
вместо простого эха.Если вы хотите сохранить сложную команду (то есть команду с пробелами или другими специальными символами в «словах»), вам нужно поместить ее в массив вместо простой текстовой переменной, а затем развернуть ее с помощью идиомы `" $ { массив [@]} ", вот так:
Теперь, если цель состоит в том, чтобы сделать простую для ввода стенографию, это явно не тот путь. Вместо этого используйте псевдоним или функцию оболочки:
или
источник
Когда bash расширяется
$dir
, он выполняет только разбиение по словам и сглаживание. Слово расщепление производит три слова:cd
,"/cygdrive/c/Program
иFiles/"
. Тогда команда для выполнения имеетcd
два аргумента;cd
только смотрит на его первый аргумент"/cygdrive/c/Program
, который не является существующим каталогом.Если вы хотите выполнить полную оценку оболочки для содержимого переменной, используйте
eval
:Обратите внимание, что вам нужны двойные кавычки
$dir
, иначе сначала произойдет разбиение слова, а затемeval
конкатенация его аргументов с пробелами. Это может сработать, но в целом будет плохо (например, если в имени файла будет два последовательных пробела).Однако строка не является правильным способом хранения команды оболочки, которую вы хотите выполнить. Если у вас нет необычного требования, вы должны использовать вместо этого функцию:
Если вы действительно заинтересованы в наборе текста
$dir
для переключения на конкретный каталог, и это не просто пример, начиная с bash 4, вставьтеshopt -s autocd
ваш.bashrc
и установитепосле чего вы можете просто
"/cygdrive/c/Program Files/"
или"$dir"
по приглашению оболочки переключиться на этот каталог. Вам все еще нужны двойные кавычки$dir
; если вам это не нравится, используйте zsh вместо bash.источник
Хранение команд в переменных, как правило, не очень хорошая идея. Вот для чего нужны функции и псевдонимы.
Скорее, чем
попробуйте один из них:
или
или
Первая форма, хранящая имя каталога в переменной, означает немного больше ввода, но она понятнее, когда вы выполняете команду, которую вы делаете
cd
. Второе ближе всего к тому, что вы пытаетесь достичь. (Я не часто использую псевдонимы в bash; на самом деле я не уверен, какое преимущество они имеют над функциями.)РЕДАКТИРОВАТЬ :
И
dir
это , вероятно , плохое имя для псевдонима или функции, так как есть существующая команда с таким именем (это в основном вариантls
, по крайней мере , если у вас есть GNU Coreutils).источник
Storing commands in variables is generally not a good idea. That's what functions and aliases are for.
Пытаться
Но даже более конкретно:
/programming/4334467/cygwin-using-a-path-variable-containing-a-windows-path-with-a-space-in-it
источник