2015-12-02 3 views
4

У меня есть смущенный.Использование Bash для отправки списка разделенных пробелами файлов в Git

Я создаю скрипт Bash, который копирует файлы в ряд репозиториев, а затем добавляет их для фиксации. Файлы иногда содержат пробелы в именах файлов, поэтому их нужно указывать.

Я создал список имен файлов, разделенных пробелами, в переменной в Bash: $x. Когда я бегу echo $x я получаю это:

'test 01.sql' 'test 02.sql' 'test_03.sql' 

Если я вручную запустить следующее (в соответствующий каталог), у меня нет никаких проблем:

git add 'test 01.sql' 'test 02.sql' 'test_03.sql' 

Но в моем сценарии, если Я запускаю:

git add $x или git add "$x" или git add "${x}", я получаю смертельную ошибку pathspec от Git.

фатальным: pathspec «» тест 01.sql «„тест 02.sql“„test_03.sql“» не найдено ни одного файла

Я пробовал как одиночные и двойные кавычки строки с нет разницы.

Пример упрощен. Полная версия использует абсолютные пути к файлам.

'/Volumes/HardDrive/Repo/queries/test 01.sql' '/Volumes/HardDrive/Repo/queries/test 02.sql' '/Volumes/HardDrive/Repo/queries/test_03.sql' 

Он работает, когда вторит из сценария и вставить вручную в мерзавец добавить команду, но не работает, когда передаются из переменных в скрипте.

+0

Чтобы лучше понять, почему Баш ведет себя так, как это делает, считает чтение http://mywiki.wooledge.org/BashParser. Или, чтобы сделать сразу уместную точку: Цитаты из расширения переменной всегда являются данными, а не синтаксисом, поскольку расширения происходят только после того, как * синтаксический синтаксический анализ завершен. (Это на самом деле является обязательным для правильности: если бы это было не так, было бы невозможно написать сценарии оболочки, безопасно обрабатывающие ненадежные данные). –

+0

http://mywiki.wooledge.org/BashFAQ/050 также имеет прямое отношение. –

+0

Кстати, откуда взялся ваш «список имен файлов, разделенных пробелами»? Если вы создаете его с помощью строковых манипуляций, код, генерирующий этот список, наверняка имеет тонкие ошибки, которые могут быть использованы с соответствующими созданными именами файлов. (Имена файлов разрешены для размещения буквенных символов кавычек, буквенных строк новой строки - ничего, кроме NUL, поэтому имя, содержащее буквенные символы '' ', может потенциально избежать его команд цитирования и запуска, иначе' ''$ $ (rm -rf.)" ', были наивно цитируемой строкой' eval''d). –

ответ

2

Список имен с оболочкой - очень плохой выбор форматов для использования в программном (в отличие от человеческого) вводах.

Это кажется неинтуитивным, но это верно по причине: при вводе команды в оболочке эта команда анализируется как код; он может содержать перенаправления, замены команд и другие расширения с потенциально опасными побочными эффектами.

Чтобы обеспечить безопасную обработку данных без риска оценки в качестве кода, оболочка выполняет только расширение параметра после. Большинство других этапов синтаксического анализа (без разделения строк результатов расширения и глобулизации) завершены.


Если вы вручную генерируя этот ввод и рассмотрение его на корректность, вы можете использовать eval:

# THIS IS DANGEROUS unless you trust your string to contain no malicious content! 
files="'test 01.sql' 'test 02.sql' 'test_03.sql'" 
eval "git add -- $files" 

Однако, если вы программно генерировать этот список, формат его в качестве NUL разделителем потока, а также использовать xargs:

# generate a list in unambiguous NUL-delimited form 
printf '%s\0' "/path/to/file 1" "/path/to/file 2" >file.txt 

# use that list to run `git add` for the named files 
xargs -0 git add -- <file.txt 

... или NU L-разделители поток может быть считан в массив оболочки:

# read that list into an array 
files=() 
while IFS= read -r -d '' filename; do files+=("$filename"); done <files.txt 

# ...and use the array 
git add -- "${files[@]}" 
+0

Я принимаю это как ответ, потому что он отвечает на исходный вопрос, касающийся передачи строки. Он также указывает, как и janos, на то, что наилучшим подходом является передача массива. Сценарий Bash кажется темным искусством. Удивительно, как трудно сделать, казалось бы, простые вещи: назначить массив переменной, передать массив в функцию, вернуть массив из функции. Другие вопросы переполнения стека помогли много, но мне интересно, не следует ли обманывать Ruby или Python и делать там тяжелые вещи? –

3

Вместо создания каскадной строки, использовать массив, например:

arr=('test 01.sql') 
arr+=('test 02.sql') 
arr+=('test 03.sql') 

Тогда вы будете иметь возможность добавлять файлы в массиве Bash с помощью:

git add "${arr[@]}" 
+0

Это прекрасно работает! Я думал, что 'git add' не будет принимать массив.Я протестировал этот подход, прежде чем спустился с кроличьей лунки, чтобы преобразовать массивы имен файлов в строки с кавычками. По-видимому, синтаксис массива Bash снова подтолкнул меня! –

+0

Нет, git не принимает массив ;-) Используя стиль записи в моем примере, оболочка расширяет массив до списка цитируемых аргументов. Git получил его, как будто вы вручную вводили аргументы в командной строке – janos

+0

Oh. Я этого не понимал. Я должен признать, что синтаксис массива Bash особенно непрозрачен, особенно когда нужно указывать или не указывать, когда использовать [@] или нет или [*], когда использовать '$ arr' или' $ {arr} 'или' "$ {arr}" 'или даже просто' arr'. Самое простое, что я направляюсь в Google. Мне нужно было вычесть 1 из переменной и присвоить ее другой переменной. Я закончил с явно субоптимальным «result = $ ((orig - 1))» (при этом все символы пробела критически важны). Трудно быть новичком Bash! Спасибо вам за помощь! –

0

ли можно просто сделать:

git add . 

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

+0

Да. Я мог бы также использовать git add -A. Но мой скрипт должен специально ориентироваться на файлы, добавленные в фиксацию, чтобы я не совершал непреднамеренные передачи других файлов, которые намеренно не были поставлены. –

Смежные вопросы