Как я могу передать несколько переменных, которые разделены пробелами, в функцию в bash? - PullRequest
0 голосов
/ 13 марта 2020

Рассмотрим этот макет:

function test() { 
    for line in $1
    do
        echo $line
    done
    for line2 in $2
    do
        echo $line2
    done
}

# This will give me a list of IDs
list=$(find testfolder/ -type f -exec grep "ID" {} + | sed "s/^.*ID:\ //g")
list2=$(find testfolder2/ -type f -exec grep "ID" {} + | sed "s/^.*ID:\ //g")

# this will not work
test list1 list2

# this will work 
for line in $line
do
    echo $line
done
for line2 in $2
do
    echo $line
done

Проблема в том, что переменные $ 1 и $ 2 в функции будут (конечно) первыми двумя идентификаторами, которые были найдены в списке.

Есть ли способ передать list и list2 в функцию и использовать их так же, как при вызове без функции?

1 Ответ

1 голос
/ 13 марта 2020

Проблема со сценариями Shell и именами файлов заключается в том, что оболочка разбивает входной поток на токены по пробелам и символам новой строки. Какие символы используются, хранится в глобальной переменной IFS, которая является аббревиатурой для разделителя поля ввода. Проблема в том, что имена файлов могут содержать пробелы и переводы строк. И если вы не правильно указали имена файлов, как это было в вашем вопросе, то имена файлов разделяются оболочкой.

Проблема

Создайте несколько файлов с пробелом:

$ touch a\ {1..3}

Если вы используете шаблон перетаскивания для итерации файлов, все в порядке:

$ for f in a\ *; do echo ►$f◄; done
►a 1◄
►a 2◄
►a 3◄

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

$ for f in $(echo a\ *); do echo ►$f◄; done
►a◄
►1◄
►a◄
►2◄
►a◄
►3◄

То же самое происходит, когда вы используете find:

$ for f in $(find . -name 'a *'); do echo ►$f◄; done
►./a◄
►2◄
►./a◄
►3◄
►./a◄
►1◄

Решение

Лучший способ прочитать список файлов - это разделить их с помощью символ, которого обычно нет в файле. Это нулевой символ $'\0'. Программа find имеет специальное действие под названием -print0 для печати имени файла с завершающим нулевым символом. А функция Bash mapfile может читать список, который разделен нулевыми символами:

$ mapfile -d $'\0' list < <(find . -name 'a *' -print0)

Теперь вы можете написать функцию, которой нужен список имен файлов.

$ inode() { for f in "$@"; do stat -c %i "$f"; done; }

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

$ inode "${list[@]}"
2638642
2638644
2638641

И это работает даже с символами новой строки в имени файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...