Перехід до каталогу за допомогою змінних bash не працює, коли імена каталогів мають пробіли


11

Скажімо, я хочу зберігати таку команду у змінній

cd "/cygdrive/c/Program Files/"

Тому я це роблю

dir="cd \"/cygdrive/c/Program Files/\""

Це повинно зберігати команду для переходу до каталогу програмних файлів, тому коли я набираю $ dir, він переводить мене до цього каталогу. Щоб переконатися, що цитати були правильно використані, я набираю

echo $dir

що дає мені

cd "/cygdrive/c/Program Files/"

Тому все повинно працювати нормально. Однак, коли я друкую,

$dir

я отримав

bash: cd: "/cygdrive/c/Program: No such file or directory

Що я роблю неправильно? Я використовую Cygwin, але я припускаю, що ця проблема стосується bash взагалі.


Спробуйте видалити лапки навколо імені каталогу та уникайте пробілу за допомогою зворотної косої лінії.
Майк Фіцпатрік

Відповіді:


8

Коротка відповідь: див. BashFAQ # 050 ("Я намагаюся поставити команду в змінну, але складні випадки завжди виходять з ладу!").

Довга відповідь: коли bash аналізує команду, вона аналізує лапки, перш ніж замінює змінні; він ніколи не повертається назад і повторно розбирає цитати у значеннях змінних, тому вони завершуються, не роблячи нічого корисного. Використання echo для перевірки команди є повністю оманливим, оскільки воно показує команду після її розбору; якщо ви хочете побачити, що насправді виконується, скористайтеся або set -xкомандами друку оболонок, як вони виконуються, або printf "%q " $dir; echoзамість простого відлуння.

Якщо ви хочете зберегти складну команду (тобто одну з пробілами чи іншими спеціальними символами у "словах"), вам потрібно помістити її в масив замість простої текстової змінної, а потім розгорнути її ідіомою `" $ { масив [@]} ", наприклад:

dir=(cd "/cygdrive/c/Program Files/")
"${dir[@]}"

Тепер, якщо мета полягає в тому, щоб зробити простий набір скорочень, це очевидно не шлях. Використовуйте псевдонім оболонки або функцію:

alias dir='cd "/cygdrive/c/Program Files/"'
dir

або

dir() { cd "/cygdrive/c/Program Files/"; }
dir

7

Коли bash розширюється $dir, він виконує лише розщеплення слів і поглиблення на ньому. Слово розщеплення виробляє три слова: cd, "/cygdrive/c/Programі Files/". Тоді команда для виконання - cdз двома аргументами; cdрозглядає лише перший аргумент "/cygdrive/c/Program, який не є існуючим каталогом.

Якщо ви хочете виконати повну оцінку оболонки на вмісті змінної, використовуйте eval:

eval "$dir"

Зауважте, що вам потрібні подвійні лапки навколо $dir, інакше спочатку виконується розбиття слів, а потім evalпоєднуються його аргументи з пробілами. Це сталося б тут, але працювало б погано (наприклад, якщо у назві файлу було два проміжки підряд).

Однак рядок не є правильним способом зберігання команди оболонки, яку ви хочете виконати. Якщо у вас немає незвичної вимоги, вам слід скористатися функцією:

dir () {
  cd "/cygdrive/c/Program Files/"
}

Якщо вам справді цікаво ввести $dirдля переходу на певний каталог, і це не просто простий приклад, оскільки bash 4, shopt -s autocdвведіть у свій .bashrcі встановіть

dir="/cygdrive/c/Program Files/"

після чого ви можете ввести просто "/cygdrive/c/Program Files/"або "$dir"в підказці оболонки, щоб перейти до цього каталогу. Вам ще потрібні подвійні лапки $dir; якщо вам це не подобається, використовуйте zsh замість bash.


6

Зберігання команд у змінних, як правило, не є хорошою ідеєю. Ось для чого призначені функції та псевдоніми.

Швидше ніж

dir="cd \"/cygdrive/c/Program Files/\""

спробуйте один із таких:

dir="/cygdrive/c/Program Files"
...
cd "$dir"

або

dir() { cd "/cygdrive/c/Program Files"; }
dir

або

alias dir='cd "/tmp/Program Files"'
...
dir

Перша форма, зберігання імені каталогу у змінній, означає трохи більше вводити текст, але зрозуміліше, коли ви виконуєте команду, яку ви виконуєте cd. Друга найближча до того, що ви намагаєтеся досягти. (Псевдоніми я не використовую багато в баші; я фактично не впевнений, яку перевагу вони мають над функціями.)

Редагувати:

І dirце, мабуть, неправильне ім’я для псевдоніму або функції, оскільки існує така команда з цим ім'ям (це в основному версія ls, принаймні, якщо у вас є GNU coreutils).


upvote forStoring commands in variables is generally not a good idea. That's what functions and aliases are for.
Rob

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