10

У меня есть скрипт-обертка, который выполняет некоторую работу, а затем передает исходные параметры другому инструменту:

#!/bin/bash
# ...
other_tool -a -b "$@"

Это работает нормально, если "другой инструмент" не запущен в подоболочке:

#!/bin/bash
# ...
bash -c "other_tool -a -b $@"

Если я назову мой скрипт-обертку так:

wrapper.sh -x "blah blup"

тогда только первый оригинальный аргумент (-x) передается "other_tool". На самом деле я не создаю подоболочку, а передаю исходные аргументы оболочке на телефоне Android, что не должно иметь никакого значения:

#!/bin/bash
# ...
adb sh -c "other_tool -a -b $@"

6 ответов6

12

Команда printf Bash имеет функцию, которая заключает в кавычки /escape / любую строку, так что, если родительский и подоболочка на самом деле bash, это должно работать:

#!/bin/bash

quoted_args="$(printf " %q" "$@")" # Note: this will have a leading space before the first arg
# echo "Quoted args:$quoted_args" # Uncomment this to see what it's doing
bash -c "other_tool -a -b$quoted_args"

Обратите внимание, что вы также можете сделать это в одной строке: bash -c "other_tool -a -b$(printf " %q" "$@")"

4

Ни одно из решений не работает хорошо. Просто передайте x/\ \ \ "b \"/aaaaa/\ 'xxx \ yyyy \'/zz \ "offf \" в качестве параметра, и они не пройдут.

Вот простая оболочка, которая обрабатывает каждый случай. Обратите внимание, как он избегает каждого аргумента дважды.

#!/usr/bin/env bash
declare -a ARGS
COUNT=$#
for ((INDEX=0; INDEX<COUNT; ++INDEX))
do
    ARG="$(printf "%q" "$1")"
    ARGS[INDEX]="$(printf "%q" "$ARG")"
    shift
done

ls -l ${ARGS[*]}
3

Измените $@ на $* . Я сделал небольшой локальный тест, и он работает в моем случае.

#!/bin/sh
bash -c "echo $*"
bash -c "echo $@"

Сохранение как test.sh и создание его исполняемого дает

$ ./test.sh foo bar
foo bar
foo

Как видите, между $* и $@ есть небольшая разница. Смотрите, например, http://ss64.com/bash/syntax-parameters.html


Для последующего вопроса в комментариях: вам нужно экранировать, например, пробел "дважды", чтобы передать строку с разделителем в качестве объединенного аргумента, например, с test.sh модифицированным для оболочки wc :

#!/bin/sh
bash -c "wc $*"

Это работает:

$ touch test\ file
$ ./test.sh -l "test\ file"
0 test file

но:

$ ./test.sh -l "test file"
wc: test: No such file or directory
wc: file: No such file or directory
0 total
2

Это терпит неудачу, потому что вы приводите массив (позиционные параметры) в строку. "$@" является магическим, потому что он дает вам каждый отдельный параметр в виде строки в правильных кавычках. Добавление дополнительного текста разрушает магию: "blah $@" - это всего лишь одна строка.

Это может приблизить вас:

cmd="other_tool -a -b"
for parm in "$@"; do cmd+=" '$parm'"; done
adb sh -c "$cmd"

Конечно, любой параметр, содержащий одну кавычку, вызовет проблемы.

2

Хорошо, больше объяснений:

$ cat /tmp/test.sh
#! /bin/bash

echo '$@='"$@"

set -v # "debug"

sh -c 'echo $@' "$@" # gremlins steal the first option

sh -c 'echo $@' -- "$@" # We defend the option with two knifes

$ bash -e /tmp/test.sh first second third
$@=first second third

sh -c 'echo $@' "$@" # gremlins steal the first option
second third

sh -c 'echo $@' -- "$@" # We defend the option with two knifes
first second third
-1
#! /bin/bash
sh -c 'other_tool -a -b "$@"' -- "$@"

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .