Переменная 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 поддерживает пространство в именах путей, заставляя это быть незавершенным).