Как перебирать аргументы в скрипте Bash

Массивы в java - это объекты, а все объекты переданы по ссылке . Чтобы действительно «скопировать» массив, вместо создания другого имени для массива, вам нужно пойти и создать новый массив и скопировать все значения. Обратите внимание, что System.arrayCopy полностью копирует 1-мерные массивы, но НЕ 2-мерные массивы. Причина в том, что 2D-массив на самом деле является 1D массивом из 1D-массивов, а arrayCopy копирует по указателям на одни и те же внутренние массивы 1D.

800
задан codeforester 10 January 2017 в 02:16
поделиться

3 ответа

Используйте "$@" для представления всех аргументов:

for var in "$@"
do
    echo "$var"
done

Это выполнит итерации по каждому аргументу и распечатает его на отдельной строке. $ ведет себя как $* за исключением того, что, когда заключено в кавычки аргументы разбиты правильно, если существуют пробелы в них:

sh test.sh 1 2 '3 4'
1
2
3 4
1312
ответ дан Robert Gamble 10 January 2017 в 02:16
поделиться

Перепишите теперь удаленного ответа VonC.

Сжатый ответ Robert Gamble имеет дело непосредственно с вопросом. Этот распространяется о некоторых проблемах с именами файлов, содержащими пробелы.

См. также: $ {1: $ +" "} в/bin/sh

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

Так, между чем различие $*, $@, "$*", и "$@"? Они все связаны с 'всеми аргументами оболочке', но они делают разные вещи. При закрытии кавычки, $* и $@ сделайте то же самое. Они рассматривают каждое 'слово' (последовательность непробела) как отдельный аргумент. Заключенные в кавычки формы очень отличаются, хотя: "$*" рассматривает список аргументов как единственную разделенную пробелом строку, тогда как "$@" рассматривает аргументы почти точно, как они были при определении на командной строке. "$@" не расширяется ни до чего вообще, когда нет никаких позиционных параметров; "$*" расширяется до пустой строки — и да, существует различие, хотя может быть трудно чувствовать его. Посмотрите больше информации ниже после введения (нестандартной) команды al.

Вторичный тезис: если необходимо обработать споры с пробелами и затем передать их на другие команды, то Вам иногда нужны нестандартные инструменты для помощи. (Или необходимо использовать массивы, тщательно: "${array[@]}" ведет себя аналогично к "$@".)

Пример:

    $ mkdir "my dir" anotherdir
    $ ls
    anotherdir      my dir
    $ cp /dev/null "my dir/my file"
    $ cp /dev/null "anotherdir/myfile"
    $ ls -Fltr
    total 0
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 my dir/
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 anotherdir/
    $ ls -Fltr *
    my dir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 my file

    anotherdir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 myfile
    $ ls -Fltr "./my dir" "./anotherdir"
    ./my dir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 my file

    ./anotherdir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 myfile
    $ var='"./my dir" "./anotherdir"' && echo $var
    "./my dir" "./anotherdir"
    $ ls -Fltr $var
    ls: "./anotherdir": No such file or directory
    ls: "./my: No such file or directory
    ls: dir": No such file or directory
    $

Почему это не работает? Это не работает, потому что оболочка обрабатывает кавычки, прежде чем это развернет переменные. Так, чтобы заставить оболочку обращать внимание на кавычки, встроенные в $var, необходимо использовать eval:

    $ eval ls -Fltr $var
    ./my dir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 my file

    ./anotherdir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 myfile
    $ 

Это становится действительно хитрым, когда у Вас есть имена файлов такой как"He said, "Don't do this!""(с кавычками и двойными кавычками и пробелами).

    $ cp /dev/null "He said, \"Don't do this!\""
    $ ls
    He said, "Don't do this!"       anotherdir                      my dir
    $ ls -l
    total 0
    -rw-r--r--   1 jleffler  staff    0 Nov  1 15:54 He said, "Don't do this!"
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 anotherdir
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 my dir
    $ 

Оболочки (все они) не делают особенно легким обработать такой материал, таким образом (странно достаточно) много программ Unix не делают хорошего задания обработки их. На Unix имя файла (единственный компонент) может содержать любые символы кроме наклонной черты и NUL '\0'. Однако оболочки сильно не поощряют пробелов или новых строк или вкладок нигде в пути. Это также, почему стандартные имена файлов Unix не содержат пробелы и т.д.

При контакте с именами файлов, которые могут содержать пробелы и другие неприятные символы, необходимо быть чрезвычайно осторожными, и я нашел давно, что мне была нужна программа, которая не является стандартной на Unix. Я называю его escape (версия 1.1 была датирована 1989-08-23T16:01:45Z).

Вот пример escape используемый - с системой управления SCCS. Это - сценарий покрытия, который делает обоих a delta (думайте регистрация), и a get (думайте контроль). Различные аргументы, особенно -y (причина, почему Вы внесли изменение) будет содержать пробелы и новые строки. Обратите внимание, что даты сценария с 1992, таким образом, это использует обратные галочки вместо $(cmd ...) нотация и не использует #!/bin/sh на первой строке.

:   "@(#)$Id: delget.sh,v 1.8 1992/12/29 10:46:21 jl Exp $"
#
#   Delta and get files
#   Uses escape to allow for all weird combinations of quotes in arguments

case `basename $0 .sh` in
deledit)    eflag="-e";;
esac

sflag="-s"
for arg in "$@"
do
    case "$arg" in
    -r*)    gargs="$gargs `escape \"$arg\"`"
            dargs="$dargs `escape \"$arg\"`"
            ;;
    -e)     gargs="$gargs `escape \"$arg\"`"
            sflag=""
            eflag=""
            ;;
    -*)     dargs="$dargs `escape \"$arg\"`"
            ;;
    *)      gargs="$gargs `escape \"$arg\"`"
            dargs="$dargs `escape \"$arg\"`"
            ;;
    esac
done

eval delta "$dargs" && eval get $eflag $sflag "$gargs"

(Я, вероятно, не использовал бы Escape вполне так полностью в эти дни - это не нужно с -e аргумент, например - но в целом, это - одно из моего более простого использования сценариев escape.)

escape программа просто производит свои аргументы, скорее как echo делает, но это гарантирует, что аргументы защищены для использования с eval (один уровень eval; У меня действительно есть программа, которая сделала удаленное выполнение оболочки, и это должно было выйти из вывода escape).

    $ escape $var
    '"./my' 'dir"' '"./anotherdir"'
    $ escape "$var"
    '"./my dir" "./anotherdir"'
    $ escape x y z
    x y z
    $ 

У меня есть другая названная программа al это перечисляет его аргументы один на строку (и это является еще более древним: версия 1.1, датированная 1987-01-27T14:35:49). Это является самым полезным при отладке сценариев, поскольку это может быть включено в командную строку для наблюдения, какие аргументы на самом деле передаются команде.

    $ echo "$var"
    "./my dir" "./anotherdir"
    $ al $var
    "./my
    dir"
    "./anotherdir"
    $ al "$var"
    "./my dir" "./anotherdir"
    $

[Добавленный: И теперь показать различие между различным "$@" нотации, вот еще один пример:

$ cat xx.sh
set -x
al $@
al $*
al "$*"
al "$@"
$ sh xx.sh     *      */*
+ al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file
He
said,
"Don't
do
this!"
anotherdir
my
dir
xx.sh
anotherdir/myfile
my
dir/my
file
+ al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file
He
said,
"Don't
do
this!"
anotherdir
my
dir
xx.sh
anotherdir/myfile
my
dir/my
file
+ al 'He said, "Don'\''t do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file'
He said, "Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file
+ al 'He said, "Don'\''t do this!"' anotherdir 'my dir' xx.sh anotherdir/myfile 'my dir/my file'
He said, "Don't do this!"
anotherdir
my dir
xx.sh
anotherdir/myfile
my dir/my file
$

Заметьте, что ничто не сохраняет исходные пробелы между * и */* на командной строке. Кроме того, обратите внимание, что можно изменить 'параметры командной строки' в оболочке при помощи:

set -- -new -opt and "arg with space"

Это устанавливает 4 опции,'-new', '-opt', 'and', и'arg with space'.
]

Хм, это - вполне длинный ответ - возможно, толкование является лучшим термином. Исходный код для escape доступный по запросу (электронная почта к firstname отмечают точкой lastname в точке Gmail com). Исходный код для al невероятно просто:

#include <stdio.h>
int main(int argc, char **argv)
{
    while (*++argv != 0)
        puts(*argv);
    return(0);
}

Это все. Это эквивалентно test.sh сценарий, который Robert Gamble показал и мог быть записан как функция оболочки (но функции оболочки не существовали в локальной версии Оболочки Bourne, когда я сначала записал al).

Также обратите внимание, что можно записать al как простой сценарий оболочки:

[ $# != 0 ] && printf "%s\n" "$@"

Условное выражение необходимо так, чтобы оно не производило вывода при передаче никакие аргументы. printf команда продолжит пустую линию только с аргументом строки формата, но программа C ничего не производит.

227
ответ дан Community 10 January 2017 в 02:16
поделиться

Обратите внимание, что ответ Роберта верен и работает в sh . Вы можете (портативно) еще больше упростить его:

for i in "$@"

эквивалентно:

for i

т.е., вам ничего не нужно!

Тестирование ($ - это командная строка):

$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d

Я впервые прочитал об этом в Unix Programming Environment от Кернигана и Пайка.

В bash, help for documents this:

for NAME [in WORDS ... ;] do COMMANDS; done

If 'in WORDS . ...;' нет, тогда 'в "$@"' предполагается.

126
ответ дан 22 November 2019 в 21:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: