LINUX.ORG.RU

bash - выполнить аргумент и вставить в выданную переменную

 


0

1

Есть вот такие вот функции

function parse_search_posts()
# filename
{
    shell_args 1 $@

    local _oldIFS="$IFS"

    IFS=$'\n'    
    
    echo_info_n "posts: "
    list_posts=(                        \
        $( grep "foo bar" "$1"          \
        | egrep -o "$grep_quoted_https" \
        | grep $site_static             \
        | uniq ) )

    post_total=${#list_posts[@]}
    echo_info "${#list_posts[@]}"

    IFS="$_oldIFS"

    if [ "$post_total" -eq "0" ]
    then
        echo_info "no posts found"
        return
    fi
}

function parse_search_descs()
# filename
{
    shell_args 1 $@

    local _oldIFS="$IFS"

    IFS=$'\n'    
    
    echo_info_n "posts: "
    list_descs=(                 \
        $( grep "bar baz" "$1"   \
        | grep "bar foo" "$1"    \
        | grep $site_static      \
        | uniq ) )

    desc_total=${#list_descs[@]}
    echo_info "${#list_descs[@]}"

    IFS="$_oldIFS"

    if [ "$desc_total" -eq "0" ]
    then
        echo_info "no descs found"
        shell_die
    fi
}

Есть еще с полдесятка таких функций, отличающиеся только переменной и командами на выполнение. Хочу их сжать в одну - шаблонную примерно так:

function parse_search_template()
# filename commands variable text
{
    shell_args 4 $@

    local _oldIFS="$IFS"

    IFS=$'\n'    
    
    echo_info_n "$text: "
    <...>=( $( eval $commands ) )

    elem_total=${#<...>[@]}
    echo_info "${#<...>[@]}"

    IFS="$_oldIFS"

    if [ "$elem_total" -eq "0" ]
    then
        echo_info "no $text found"
        shell_die
    fi
}

Как мне в функцию прокинуть переменную <variable> чтобы в нее писалось? Если нельзя прокинуть переменную напрямую, то как можно это обойти?

Да, только bash. Perl\Python\etc лесом.

★★★★★

Передаёте в функцию имя переменной, а пишите eval-ом.

foo() {
        local __make_name __rezult

        __make_name=$1
        ...
        __rezult="$2+bar"
        ...
        eval $__make_name=\$__rezult
}

var=value
foo var xxx

$ echo «$var»

xxx+bar

vodz ★★★★★
()
Ответ на: комментарий от vodz

Не будет проблемы в том что у меня должен передаваться массив? Вообще разницы нет? Я плюс еще краем уха слышал что в 4.3 что-то вкусное связанное с declare сотворили как раз для таких случаев

PPP328 ★★★★★
() автор топика

Правильный ответ: Вам не нужно «прокидывать переменную», а необходимо вернуть из функции результат штатным для Shell/BASH образом - через STDOUT и записать этот результат в одномерный массив:

parse_search_template () {
  echo -e "a b c\nd e f\ng h i"
}
IFS=$'\n' readarray lstResult=($(parse_search_template))
DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

Нельзя просто так взять и переустановить IFS! А если ее возвращать на место перед этим сохранив то во внешний вызов вы уже перетянули 90% функционала который я хотел спрятать в функцию.

Плюс мне еще надо проверять сколько элементов в массиве. По-вашему я опять таки должен это делать снаружи.

PPP328 ★★★★★
() автор топика
Последнее исправление: PPP328 (всего исправлений: 1)
Ответ на: комментарий от PPP328

В данном случае значение IFS - локально для команды readarray. Проверьте: после выполнения readarray IFS остаётся прежним.

DRVTiny ★★★★★
()
Ответ на: комментарий от PPP328

Никто Вам не запрещает формировать локальный массив внутри функции и выплёвывать его содержимое, заодно что-то отправляя на STDERR.

Хотя да, в данном случае я бы сделал всё-таки проверку на «пустоту» массива снаружи, но вообще это уже Ваше личное дело.

Я так вообще делал в нескольких функциях на выходе declare -p сформированного ассоциативного массива - и применял его в вызывающей функции, заменяя имя массива на нужное мне.

Но это изврат, и он был нужен для извращённых случаев. У Вас же всё просто как три копейки - и нет никакой необходимости делать что-то нестандартным образом.

DRVTiny ★★★★★
()
Ответ на: комментарий от DRVTiny

Правильный ответ

Какая чушь. Это правильно, когда вывод из внешней команды. Локально же у вас получилось изврат ради изврата. Уж лучше просто тупо писать в глобальную переменную, специально заведенную для этой «функции», чем извращаться с сопроцессом и эмуляцией пайпа руками.

vodz ★★★★★
()
Ответ на: комментарий от vodz

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

P.S. Если что-то работает единообразно: с выводом ли из «внешней команды» или локально - это, вообще говоря, хорошо. Просто до этого нужно... дорасти что ли.

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

По-моему моя одна строчка кода выглядит просто и элегантно

Во-первых, хитрая «строчка» не должна быть в основном теле программы, это уже не элегантно. В основном теле должно быть cmd var args... Во-вторых, какая-же это bash-элегантность, когда вместо встроенных shell операций предполагается echo + read? Скажите откровенно, что вы просто не умеете eval, только и всего. А как и всё невыученное, то и кажется непредсказуемо и неэлегантно. Какой бы чушью это не было.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Вы не слышали, что у BASH есть определённая концепция передачи аргументов в функцию и возврата результатов из неё?

Ваш вариант был бы просто великолепен, если бы это был код на каком-нибудь школопаскале, и переменная передавалась бы по значению или по ссылке. Но таки да, не все языки программирования - это школопаскаль. У языка оболочки есть определённое соглашение: результат выполнения функции можно вернуть либо через поток вывода, либо через глобальные переменные, либо через то и другое.

Всё остальное - не соответствует концепции языка и потому реализуется, мягко говоря, уродливо как с точки зрения синтаксиса, так и с точки зрения реализации. Например, eval может подсунуть немало презабавнейших сюрпризов. Вот ответьте мне, как любитель eval'а, сколько проходов BASH делает для обычной интерпретации и сколько - для eval.

Да, и ещё расскажите мне, несведущему, как бы это так передать в eval код, в котором есть двойные и одинарные кавычки? Я имею в виду - код, не сформированный где-то сбоку заранее? ;)

DRVTiny ★★★★★
()
Ответ на: комментарий от DRVTiny

результат выполнения функции можно вернуть либо через поток вывода, либо через глобальные переменные, либо через то и другое.

Результат работы функции - целая переменная в $? . Всё остальное - соглашение внутри самой программы, ибо количество изменяемых переменных в отличии от паскаля в shell определяется и соглашениями и в основном качеством кода :) А вот передача результатов через echo+read - объяснено ранее.

сколько проходов BASH делает для обычной интерпретации и сколько - для eval.

По сравнению с fork+write+read ? Да на много порядков меньше.

Да, и ещё расскажите мне, несведущему, как бы это так передать в eval код, в котором есть двойные и одинарные кавычки? Я имею в виду - код, не сформированный где-то сбоку заранее? ;)

Да пожалуйста, заодно ответ на bash - выполнить аргумент и вставить в выданную переменную (комментарий) для PPP328:

#!/bin/bash
declare -a var

foo() {
        eval local -a __rezult=(\${$1[@]})
        local i r

        for ((i=0;i<${#__rezult};i++)); do
#                echo "${__rezult[i]}"
                r="${__rezult[i]}+$2"
                eval $1[i]=\$r
        done
}

var=(value1\" value2\')
foo var xxx\"\'zzz
echo ${var[0]} ${var[1]}
value1"+xxx"'zzz value2'+xxx"'zzz

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

По сравнению с fork+write+read ? Да на много порядков меньше.

Как только Вы мне выкатите бенчмарк, который, раз уж это так мега-важно для кода на BASH, сравнивает «оптимальность» Вашего кода и моего - будет о чём говорить. А так пока сакральные знания про fork не очень Вам помогают быть чуточку умнее.

Да пожалуйста, заодно ответ

Вы уж извините, но этот код и выглядит, и работает как Г.

А вот это:

for ((i=0;i<${#__rezult};i++)); do
- просто не будет работать.

И да, если ответ как-либо касался вопроса про интепретацию кода, содержащего кавычки, то Вы просто тупняк гоните, потому что вот это:

eval local -a __rezult=(\${$1[@]})
eval $1[i]=\$r
- не содержит кавычек.

И да, подумайте на досуге, что будет делать eval в зависимости от содержимого $1, если учесть, что в $1 может содержаться вообще всё, что угодно.

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

А вот это:

Это была обычная опечатка, код был write only пятиминутный.

А так пока сакральные знания про fork не очень Вам помогают быть чуточку умнее.

Вы просто тупняк гоните

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

vodz ★★★★★
()
Ответ на: комментарий от vodz

Как же я забыл, что на лоре главное не аргументы, а побольше хамства.

Я не склонен к хамству. Договорились, Вы несёте чушь. Вам же это больше нравится?

Объясните, пожалуйста, будьте так любезны и добры, каким образом Ваш прекрасный во всех отношениях пример демонстрирует выполнение в eval кода, включающего разные виды кавычек?

DRVTiny ★★★★★
()
Ответ на: комментарий от vodz

Чет вообще до примитива сократил и не бубырчит:

#!/bin/bash

function parse_search_template()
# variable
{
    local _varname="$1"
    local _comname="echo aaa | grep aaa"
    local _elemtotal

    eval $_varname=( $( $_comname ) )

    eval _elem_total=${#_varname[@]}
    echo "$_elemtotal"
}

parse_search_template myarr1

Так ругается на

./test.sh: строка 10: ошибка синтаксиса около неожиданной лексемы `('
./test.sh: строка 10: `    eval $_varname=( $( $_comname ) )'

Какой бы бакс я не экранировал - без толку.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Все, разрулил:

#!/bin/bash

function parse_search_template()
# variable
{
    local _varname="$1"
    local _comname="echo aaa | grep aaa"
    local _elemtotal

    eval "$_varname=( \$( $_comname ) )"

    eval _elemtotal=( ${#_varname[@]} )
    echo "$_elemtotal"
}

parse_search_template myarr1

echo ${myarr1[0]}
./test.sh 
1
aaa

Всем спасибо!

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Все, разрулил:

Ну да, 5 минут убил на то, что в одном месте в предыдущем примере у вас было _elemtotal, а в другом _elem_total... :)

eval «$_varname=( \$( $_comname ) )»

Это не будет работать, если в тексте будут кавычки, лучше: eval $_varname=\(\$\(\$_comname\)\)

eval _elemtotal=( ${#_varname[@]} )

Это что такое, как оно у вас работало? Наверное имелось в виду: eval _elemtotal='${#'$_varname'[@]}' ?

vodz ★★★★★
()
Ответ на: комментарий от DRVTiny

Объясните, пожалуйста, будьте так любезны и добры, каким образом Ваш прекрасный во всех отношениях пример демонстрирует выполнение в eval кода, включающего разные виды кавычек?

Тренируетесь отжимать мобильники в подворотнях? Стиль один в один.

В примере было продемонстрировано условия ТС-а и ваших: как входные аргументы, как и дополнительные строки с кавычками для получения результата: массива со строками, включая оба типа кавычек.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Ну да, 5 минут убил на то, что в одном месте в предыдущем примере у вас было _elemtotal, а в другом _elem_total... :)

А я до этой строчки так и не дошел. Раньше падало :)

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Ещё одним говнокодером стало больше. Аминь.

DRVTiny ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.