The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



"Как передать несколько путей с пробелами через переменную?"
Версия для распечатки Пред. тема | След. тема
Форум Открытые системы на рабочей станции
Исходное сообщение [ Отслеживать ]

. "Как передать несколько путей с пробелами через переменную?" +/
Сообщение от And (??), 01-Июн-20, 21:14 
> И IFS трогать ненужно и, по идее, там даже переносы строк
> не помеха.

Да. Кавычки расставлены так, что при разворачивании всё оказывается целыми строками, независимо от наличия IFS или других специальных символов внутри значений. Различие между @ и * при развёртке массива.

Не трогая IFS можно вот так (Zenity заменена на find, для примера):


while read filename ; do
    echo "I found name: '${filename}'"
done <<< "$( find /tmp -maxdepth 1 )"

В зависимости от реализации сам(и) IFS можно тронуть, если явно удобно. Если каждая строка это реально отдельный элемент массива (что не всегда), то можно вот так, с бэкапом IFS, если нужен:

Синтаксис описан здесь: https://wiki.bash-hackers.org/syntax/arrays


#!/bin/bash

mkdir "/tmp/asd fgh" "/tmp/qwe rty"

IFS_back="${IFS}"
IFS=$'\n'
declare -a strings_array=($( ls -1 /tmp ))
for single_string in "${strings_array[@]}" ; do
    if [[ "${single_string}" =~ ^"asd".*|.*" rty"$ ]] ; then  # Прячу прочее содержимое своего /tmp, показываю только нужные имена.
        echo $single_string
    fi
done
IFS="${IFS_back}"


В зависимости от идеи бывает нужно сохранить для обработки позже. Причём IFS не трогается. Но больше вычислений - медленнее. Можно так:


declare -a str_array=()
while read filename ; do
    str_array+=("${filename}")
done <<< "$( find /tmp -maxdepth 1 )"
echo "${str_array[0]}"
echo "${str_array[1]}"
echo "Total found: ${#str_array[@]}"

Либо ещё сильнее:


declare -A str_map=()
while read path ; do
    str_map[$path]=$( basename "${path}" )
done <<< "$( find /tmp -maxdepth 1 )"

for dir_name in "${!str_map[@]}" ; do
    echo "Have file '${str_map[$dir_name]}' in '$(dirname "${dir_name}")'"
done
echo "Total found: ${#str_map[@]}"

Иногда по логике полезно применять логгирование и свал скрипта на первом возврате ошибки (рекомендации от Debian), объявления переменных readonly. Это позволяет гораздо меньше морочиться обработкой ошибок и быстрее их находить.


#!/bin/bash
PS4="+:$( basname \"\${0}\" ):\${LINENO}: "
set -xeu -o pipefail
declare -r some_name="asdfgh"

Применяется всё это примерно вот так:


#!/bin/bash

PS4="+:$( basename \"\${0}\" ):\${LINENO}: "
set -xeu -o pipefail

function do_did_done {
    local -A str_map
    while read path ; do
        str_map[$path]=$( basename "${path}" )
    done <<< "$( find /tmp -maxdepth 1 )"
    total_found="${#str_map[@]}"
}

total_found=0
do_did_done

set +e  # Выключил свал.
false  # Сгенерировал код возврата ошибка, а оно не падает.

echo "ИНФОРМАЦИЯ:${0}:${LINENO}: Total found ${total_found}"  # Не залоггировало саму команду т.к. set +x

set -e  # Включил свал обратно.  Осторожно, при определённых условиях внутрь функции не наследуется.
set -x  # Чтобы показало, на чём оно упадёт
declare -r dir_name="никогда-не-было-такой-директории"
test -d "${dir_name}"  # А вот тут упало, с очень показательной диагностикой, т.к. set -e !!!

echo "Сюда уже не дойдёт."

По причине '<<<' - это Bash код.
По причине "declare -A" - это версия Bash 4+

До встречи в продакшн!! :)

P.S. Отвечая на старинный вопрос: зачем Вы используете эти башизмы '<<<'? Т.к. при таком приёме переменная, объявленная внутри цикла, сохранится по окончании цикла. Спасибо Opennet, здесь ведь научился.

Ответить | Правка | Наверх | Cообщить модератору

Оглавление
Как передать несколько путей с пробелами через переменную?, inFlowiaLab, 28-Май-20, 19:11  [смотреть все]
Форумы | Темы | Пред. тема | След. тема



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру