строить списки аргументов, содержащие пробелы - PullRequest
8 голосов
/ 04 января 2009

В bash можно экранировать аргументы, содержащие пробелы.

foo "a string"

Это также работает для аргументов команды или функции:

bar() {
    foo "$@"
}

bar "a string"

Пока все хорошо, но что, если я хочу манипулировать аргументами перед вызовом foo?

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

bar() {
    for arg in "$@"
    do
        args="$args \"prefix $arg\""
    done

    # Everything looks good ...
    echo $args

    # ... but it isn't.
    foo $args

    # foo "$args" would just be silly
}

bar a b c

Итак, как вы строите списки аргументов, когда аргументы содержат пробелы?

Ответы [ 5 ]

16 голосов
/ 05 января 2009

Есть (как минимум) два способа сделать это:

  1. Используйте массив и разверните его, используя "${array[@]}":

    bar() {
        local i=0 args=()
        for arg in "$@"
        do
            args[$i]="prefix $arg"
            ((++i))
        done
    
        foo "${args[@]}"
    }
    

    Итак, что мы узнали? "${array[@]}" равно ${array[*]} что "$@" равно $*.

  2. Или, если вы не хотите использовать массивы, вам нужно использовать eval:

    bar() {
        local args=()
        for arg in "$@"
        do
            args="$args \"prefix $arg\""
        done
    
        eval foo $args
    }
    
4 голосов
/ 03 октября 2013

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

(пример: создание аргументов для команды find)

dir=$1
shift
for f in "$@" ; do
    args+=(-iname "*$f*")
done
find "$dir" "${args[@]}"
2 голосов
/ 04 января 2009

Использование массивов (одна из скрытых функций в Bash).

0 голосов
/ 06 января 2009

У меня тоже была проблема с этим. Я писал сценарий bash для резервного копирования важных файлов на моем компьютере с ОС Windows (cygwin). Я тоже попробовал подход с массивами, но у меня все еще были проблемы. Не уверен, как именно я это исправил, но вот части моего кода, которые важны в случае, если он поможет вам.

WORK="d:\Work Documents\*"
#   prompt and 7zip each file
for x in $SVN $WEB1 $WEB2 "$WORK" $GRAPHICS $W_SQL
do
    echo "Add $x to archive? (y/n)"
    read DO
    if [ "$DO" == "y" ]; then
        echo "compressing $x"
        7zip a $W_OUTPUT "$x"
    fi
    echo ""
done
0 голосов
/ 06 января 2009

Вы можете использовать массивы так, как вы предлагаете, с небольшими изменениями деталей. Строка, вызывающая foo, должна иметь вид

 foo "${args[@]}"
...