Переменная Shell с пробелами, для одной опции командной строки
У сценариев Autoconf возникают проблемы с именем файла или именем пути с пробелами. Например,
./configure CPPFLAGS="-I\"/path with space\""
приводит к (config.log):
configure:3012: gcc -I"/path with space" conftest.c >&5
gcc: with: No such file or directory
gcc: space": No such file or directory
Команда компиляции из. /configure - это ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
, и я не могу ее изменить (возможно, но, возможно, работа над autoconf не является общим решением).
Я думаю, что это сводится к получению переменной оболочки, которая содержит пробелы, которые будут анализироваться как одна переменная командной строки, а не разделены на пробелы. Самый простой пример оболочки, который я могу придумать, - создать файл с пробелами и попытаться перечислить с помощью ls
с переменной оболочки в качестве аргумента ls
:
$ touch "a b"
$ file="a b"
$ ls $file
ls: a: No such file or directory
ls: b: No such file or directory
Это работает, но является незаконным, поскольку в autoconf я не могу изменить код оболочки:
$ ls "$file"
a b
Ни одна из следующих попыток при цитировании вещей не работает:
$ file="\"a \"b"; ls $file
ls: "a: No such file or directory
ls: b": No such file or directory
$ file="a\ b"
$ file="a\\ b"
$ file="`echo \\"a b\\"`"
и т.д.
Невозможно ли выполнить скрипты оболочки? Есть ли магическое цитирование, которое расширяет переменную оболочки с пробелами в один аргумент командной строки?
Ответы
Ответ 1
Вам следует попытаться установить переменную среды $IFS
.
от человека bash (1):
IFS - внутренний разделитель полей, который используется для разбиения слов после расширения и разделить строки на слова с помощью read builtin команда. По умолчанию используется значение '' space tab newline ''.
Например
IFS=<C-v C-m> # newline
file="a b"
touch $file
ls $file
Не забудьте установить $IFS
назад или странные вещи.
Ответ 2
если вы дадите команду
gcc -I"x y z"
в оболочке, то, конечно, один параметр командной строки "-Ix y z" будет передан gcc. Это не вопрос. То, что весь смысл двойных кавычек: вещи внутри двойных кавычек НЕ подлежат расщеплению поля и, таким образом, не подвержены $IFS, например.
Но вам нужно быть осторожным в отношении количества котировок, которые вам нужны. Например, если вы скажете
file="a b" # 1
а затем вы скажете
ls $file # 2
происходит то, что содержимое переменной файла является "a b", а не "b" , потому что двойные кавычки были "съедены", когда была проанализирована строка 1. Замененное значение затем разделяется по полю, и вы получаете ls на два файла "a" и "b" . Правильный способ получить то, что вам нужно, -
file="a b"; ls "$file"
Теперь проблема в исходном случае заключается в том, что когда вы устанавливаете переменную в строку, содержащую двойные кавычки CONTAINS, двойные кавычки позже не интерпретируются как символы кодовых символов, а также как обычные буквы. Вот почему, когда вы делаете что-то вроде
file="\"a b\""; ls $file
на самом деле оболочка токенизирует содержимое переменной файла в "a" и "b" , когда анализируется команда ls; двойная кавычка больше не является символом кавычки оболочки, а просто частью содержимого переменной. Это аналогично тому, если вы установили
file="\$HOME"; ls $file
вы получите сообщение об ошибке, что каталог $HOME не существует --- не выполняется поиск переменных среды.
Итак, ваши лучшие варианты
- Hack autoconf
- Не используйте имена путей с пробелами (лучшее решение)
Ответ 3
Использование пространства в именах каталогов в мире Unix просто требует неприятностей. Это не просто проблема цитирования в сценариях оболочки (что в любом случае необходимо сделать правильно): некоторые инструменты просто не могут справиться с пробелами в именах файлов. Например, вы не можете (переносимо) написать правило Makefile
, которое говорит build "baz.o
" с "foo bar/baz.c
".
В случае CPPFLAGS
выше я бы в порядке предпочтения:
- исправить неполадку системы, использовать любое пространство в именах каталогов
- напишите небольшую оболочку вокруг компилятора и вызовите
./configure CC=mygcc
. В этом случае mygcc
может быть
!/bin/sh
gcc "-I/foo bar/include" "[email protected]"
- создайте символическую ссылку (например,
/tmp/mypath
) на страшный путь и используйте CPPFLAGS=-I/tmp/mypath
Ответ 4
Вы хотите процитировать весь аргумент одним из следующих способов:
./configure "CPPFLAGS=-I/path with space"
./configure CPPFLAGS="-I/path with space"
Затем команда ./configure
видит один аргумент
"CPPFLAGS=-I/path with space"
который анализируется как параметр с именем «CPPFLAGS»
, имеющий значение «-I/path with space»
(скобки добавлены для ясности).
Ответ 5
Использование цитат интересно. Из (слегка) чтения справочной страницы bash я думал, что вам нужно избегать пространства с \, поэтому "/path with space" становится /path \with\space Я никогда не пробовал кавычки, но кажется, что это не так В целом (ваш пример). Escaping работает с ls без цитирования и без изменения IFS.
Что произойдет, если вы используете формат команды "escaping spaces"?
Ответ 6
$ file="\"a b\""
$ eval ls $file
Ответ 7
Все зависит от того, как используется переменная. Во-первых, обратите внимание, что если вы используете Autoconf, это, вероятно, означает, что в конце будет использоваться make
, так что правила продиктованы make
и, в частности, стандартными правилами make
. Даже если вы можете использовать свои собственные правила исключительно, вещи должны оставаться согласованными между инструментами, а некоторые переменные имеют стандартные значения, так что вы не хотите отклоняться от них. Это не относится к CPPFLAGS
, но это должно быть похоже на CFLAGS
, что является стандартным. См. Утилиту POSIX make
, где переменные просто расширены стандартным расщеплением слов sh
, которое не предоставляет никакого механизма цитирования (поле разделитель управляется $IFS
, но не меняет переменную IFS
, чтобы принимать пробелы как обычные символы, так как это нарушит другие вещи, например, возможность предоставить несколько параметров -I
и/или -L
в таких переменных с помощью стандартный способ).
Поскольку существует такое ограничение с make
, я полагаю, что было бы бесполезно пытаться избежать этого ограничения в Autoconf.
Теперь, поскольку пространство обязательно является разделителем полей, единственная возможность - указать пути без пробелов. Если бы пробелы в именах путей должны были поддерживаться в будущем, это, вероятно, было бы выполнено с помощью кодирования имени пути с расшифровкой на пользовательском интерфейсе высокого уровня (немного похоже на URL-адреса). В качестве альтернативы, если у вас есть выбор и вы действительно хотите использовать пробелы в именах путей, вы можете использовать некоторое пространство, отличное от ASCII (BTW, так как RISC OS поддерживает пространство в именах путей, заставляя это быть незавершенным).