Сохранение пробелов в строке в качестве аргумента командной строки - PullRequest
7 голосов
/ 12 октября 2009

Я столкнулся с небольшой проблемой, я хочу передать строку, содержащую пробелы, в другую программу, так что вся строка рассматривается как аргумент командной строки.

Короче говоря, я хочу выполнить команду следующей структуры через скрипт оболочки bash: имя_команды -a arg1 -b arg2 -c "Аргумент с пробелами здесь"

Но как бы я ни старался, пробелы не сохраняются в строке и по умолчанию токенизируются. Решение пожалуйста,

edit: Это основная часть моего скрипта:

#!/bin/bash

#-------- BLACKRAY CONFIG ---------------#
# Make sure the current user is in the sudoers list
# Running all instances with sudo

BLACKRAY_BIN_PATH='/opt/blackray/bin' 
BLACKRAY_LOADER_DEF_PATH='/home/crozzfire'
BLACKRAY_LOADER_DEF_NAME='load.xml'
BLACKRAY_CSV_PATH='/home/crozzfire'
BLACKRAY_END_POINT='default -p 8890'
OUT_FILE='/tmp/out.log'

echo "The current binary path is $BLACKRAY_BIN_PATH"


# Starting the blackray 0.9.0 server
sudo "$BLACKRAY_BIN_PATH/blackray_start"

# Starting the blackray loader utility
BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "\"$BLACKRAY_END_POINT\"""

sudo time $BLACKRAY_INDEX_CMD -a $OUT_FILE

#--------- END BLACKRAY CONFIG ---------#

Ответы [ 6 ]

5 голосов
/ 12 октября 2009

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

sudo time $BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT" -a $OUT_FILE

Если вам действительно нужно сохранить команду и использовать ее позже, есть несколько вариантов;В вики bash-hackers.org есть хорошая страница по теме .Мне кажется, что наиболее полезным здесь является помещение команды в массив, а не в простую переменную:

BLACKRAY_INDEX_CMD=($BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT")

sudo time "${BLACKRAY_INDEX_CMD[@]}" -a $OUT_FILE

Это позволяет избежать путаницы между пробелами-разделителями-словами и пробелами-в-словахпотому что слова не разделены пробелами - они находятся в отдельных элементах массива.Расширение массива в двойных кавычках с суффиксом [@] сохраняет эту структуру.

(Кстати, другой вариант - использовать экранированные кавычки, как вы делаете, затем выполнить команду с eval.Не делайте этого, это хороший способ ввести странные ошибки при разборе.)

2 голосов
/ 23 ноября 2012

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

# iterate through the passed arguments, save them to new properly quoted ARGS string
while [ -n "$1" ]; do
   ARGS="$ARGS '$1'"
   shift
done

# invoke the command with properly quoted arguments
my_command $ARGS
1 голос
/ 12 октября 2009

Редактировать

Попытка:

BLACKRAY_END_POINT="'default -p 8890'"

или

BLACKRAY_END_POINT='"default -p 8890"'

или

BLACKRAY_END_POINT="default\ -p\ 8890"

или

BLACKRAY_END_POINT='default\ -p\ 8890'

и

BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e $BLACKRAY_END_POINT"

Оригинальный ответ :

Является ли blackray_loader сценарием оболочки?

Вот демонстрация того, что вам приходится иметь дело с этой проблемой как при указании параметра, так и при его обработке:

Текстовый файл с именем «test.txt» (включая номера строк):

1 two words
2 two        words
3 two
4 words

Скрипт под названием "spacetest":

#!/bin/bash
echo "No quotes in script"
echo $1
grep $1 test.txt
echo

echo "With quotes in script"
echo "$1"
grep "$1" test.txt
echo

Запустить его с ./spacetest "two--------words" (заменить дефисы пробелами):

No quotes in script
two words
grep: words: No such file or directory
test.txt:1 two words
test.txt:2 two        words
test.txt:3 two

With quotes in script
two        words
2 two        words

Вы можете видеть, что в разделе «Без кавычек» он попытался сделать grep two words test.txt, который интерпретировал «слова» как имя файла в дополнение к «test.txt». Кроме того, echo опустил лишние пробелы.

Когда параметр заключен в кавычки, как во втором разделе, grep видел его как один аргумент (включая лишние пробелы) и обрабатывал его правильно. И echo сохранил лишние пробелы.

Кстати, я использовал лишние пробелы просто для помощи в демонстрации.

1 голос
/ 12 октября 2009

вероятно, вам нужно заключить аргумент в двойные кавычки (например, "$ {6}").

После комментария OP это должно быть "$ BLACKRAY_END_POINT"

0 голосов
/ 29 января 2015

Ниже приведен мой пример перезапуска скрипта с помощью exec su USER или exec su - USER . Вмещает:

  • вызывается из относительного пути или текущего рабочего каталога
  • пробелы в имени скрипта и аргументах
  • одинарные и двойные кавычки в аргументах, без сумасшедших выходов вроде: \\ "

#
# This script should always be run-as a specific user
#
user=jimbob
if [ $(whoami) != "$user" ]; then
  exec su -c "'$(readlink -f "$0")' $(printf " %q" "$@")" - $user
  exit $?
fi
0 голосов
/ 27 июня 2014

Сообщение в другом блоге спасло меня от этой проблемы пробелов: http://logbuffer.wordpress.com/2010/09/23/bash-scripting-preserve-whitespaces-in-variables/

По умолчанию пробелы обрезаются:

bash> VAR1="abc        def    gh ijk"
bash> echo $VAR1
abc def gh ijk
bash>

"Причиной такого поведения является внутренняя переменная оболочки $ IFS (Разделитель внутренних полей) , которая по умолчанию имеет пробел, табуляцию и символ новой строки. Чтобы сохранить все смежные пробелы , вы должны установить IFS на что-то другое"

С IFS обход:

bash> IFS='%'
bash> echo $VAR1
abc        def    gh ijk
bash>unset IFS
bash>

Это прекрасно работает для моего командного случая:

su - user1 -c 'test -r "'${filepath}'"; ....'

Надеюсь, это поможет.

...