функция goto

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Ответить
Аватара пользователя
olecya
Сообщения: 900
ОС: debian, fedora (i3-wm)

функция goto

Сообщение olecya »

На одном забугорном форуме при миграции движка, всплыла прошлогодняя тема оставшаяся для меня
не замеченной. Реализация функции goto, как заявлено для dash, bash и ksh. Проверяла только
на bash в linux и ksh93 во freebsd.

Код: Выделить всё

#!/usr/local/bin/dash
# goto_demo.sh

# goto ': some_label:'
goto()
{
    line_number=1
    start_line=1
    while IFS='' read -r line
    do
        if [ "${line}" = "${1}" ]
        then
            : > /tmp/goto.tmp
            start_line=${line_number}
        fi
        if [ ${line_number} -ge ${start_line} ]
        then
            echo "${line}" >> /tmp/goto.tmp
        fi
        line_number=$(( line_number + 1 ))
    done
    . /tmp/goto.tmp
} < ${0}

goto ': second:'
echo 'This will not be printed!'
: first:
echo '**************************************'
echo 'You are at first label!'
# cat /tmp/goto.tmp
echo '**************************************'
goto ': third:'
echo 'This will not be printed either!'
: second:
echo '**************************************'
echo 'You are at the second label!'
# cat /tmp/goto.tmp
echo '**************************************'
goto ': first:'
echo 'And finally, this will not be printed either!'
: third:
echo '**************************************'
echo 'You are at the third label!'
echo '######## cat /tmp/goto.tmp... ########'
cat /tmp/goto.tmp
echo '###### END cat /tmp/goto.tmp... ######'
echo '**************************************'
: end:
echo 'Exiting...'
echo '**************************************'
exit
Результат работы скрипта:

Код: Выделить всё

./goto_demo.sh
**************************************
You are at the second label!
**************************************
**************************************
You are at first label!
**************************************
**************************************
You are at the third label!
######## cat /tmp/goto.tmp... ########
: third:
echo '**************************************'
echo 'You are at the third label!'
echo '######## cat /tmp/goto.tmp... ########'
cat /tmp/goto.tmp
echo '###### END cat /tmp/goto.tmp... ######'
echo '**************************************'
: end:
echo 'Exiting...'
echo '**************************************'
exit
###### END cat /tmp/goto.tmp... ######
**************************************
Exiting...
**************************************
Предложена оптимизация:

Код: Выделить всё

goto()
{
    line_copy=
    while IFS='' read -r line
    do
        [ "$line" = "$1" ] && line_copy=1
        [ -n "$line_copy" ] && echo "$line"
    done < "$0" > /tmp/goto.tmp
    . /tmp/goto.tmp
}
Подумалось может кому будет интересно повозиться и придумать свою реализацию.
Конечно с временным файлом хак выглядит довольно органично но может варианты
через переменные или неименованный канал будут не на много сложнее? В любом
случае это интересно.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20752
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: функция goto

Сообщение Bizdelnick »

А зачем? Не припоминаю ни одного случая, когда бы мне такое могло пригодиться.
С неименованным каналом сходу приходит в голову только bash-only вариант (. <( ... )), а много думать неохота ввиду бесполезности.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
Vascom
Сообщения: 1699
ОС: Fedora 32

Re: функция goto

Сообщение Vascom »

Сообщение удалено.
Последний раз редактировалось Vascom 27.06.2020 07:34, всего редактировалось 1 раз.
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 900
ОС: debian, fedora (i3-wm)

Re: функция goto

Сообщение olecya »

Bizdelnick писал:
09.05.2020 13:07
А зачем?
Наверное я не совсем ясно раскрыла тему. На мой взгляд интересная академическая задача,
мне нравятся такие вещи даже не смотря на их практическую бесполезность. Но именно анализ таких тем
позволяет не теряться в не стандартной ситуации при боевых условиях. Топик направлен не к профессионалам,
чьё время - деньги, а как пример креативного мышления - хорошего двигателя в познании. Ну и естественно
в первую очередь к тем кто хотя бы частично разделяет такое мнение, возможно скучает и может заинтересоваться.
Vascom писал:
09.05.2020 13:14
То есть вас не учили, что goto - зло в любом виде?
Думаю ответ выше покрывает и ваш вопрос. Спасибо что делитесь своим мнением.
Добавлено (14:34):
Bizdelnick писал:
09.05.2020 13:07
приходит в голову только bash-only вариант (. <( ... ))
Да с переменной это работает. Возможно есть такой же простой вариант с дескриптором
неименованного канала? exec 5<> <(:)
Добавлено (15:05):
Вот такой вариант мне кажется может быть удобным из за двух опций -n и -s команды mapfile
cat file

Код: Выделить всё

echo one
echo two
echo three
echo four
echo five
echo six
echo seven
echo eight
cat test.sh

Код: Выделить всё

#!/bin/bash
mapfile -n3 -s4 <file
. <(echo "${MAPFILE[@]}")
./test.sh

Код: Выделить всё

five
six
seven
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 900
ОС: debian, fedora (i3-wm)

Re: функция goto

Сообщение olecya »

Исключить темп файл с помощью sed и переменной оказалось очень просто

Shell

goto()
{
tmp="$(sed "/^$1"'/,$!d' $0)"
. <(echo "$tmp")
}
Добавлено (16:44):
Да нет, даже так!
goto() { . <(sed "/^$1"'/,$!d' $0); }
:rolleyes:
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2604
ОС: Gentoo

Re: функция goto

Сообщение ormorph »

Довольно бесполезное занятие, ну да ладно.

Код: Выделить всё

goto(){
	eval "$(sed "1,$[$1-1]d" $0)"
}
Для совместимости с bourne shell:

Код: Выделить всё

goto(){
	. <(sed "1,$(($1-1))d" $0)
}
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3729
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2
Контактная информация:

Re: функция goto

Сообщение Hephaestus »

olecya писала:
09.05.2020 14:23
На мой взгляд интересная академическая задача,
мне нравятся такие вещи даже не смотря на их практическую бесполезность.
Не-а. Скрипты бывают очень медленными.
Я как-то взялся реализовать на bash конвертацию определенного html-файла в определенный xml-файл.
Там нужно было делать разбор строк и внутри строк ещё обрабатывать отдельные слова.
Получилось весьма неторопливо - несколько десятков файлов обрабатывались... короче, ждать надоело.
У других ребят на python получилось ощутимо быстрее.
А я ещё пробовал сделать на FreePascal - получилось ещё быстрее.
Это я к тому, что обработка кучи файлов именно средствами bash c ковырянием внутри файла - не самая удачная затея, даже из академического интереса.

Я не очень понял, какую именно задачу решает исходный скрипт,
но если эта строчка
olecya писала:
09.05.2020 16:39
goto() { . <(sed "/^$1"'/,$!d' $0); }
делает то же самое, тогда скрипт вообще интереса не представляет. Бессмысленная портянка и больше ничего.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2604
ОС: Gentoo

Re: функция goto

Сообщение ormorph »

Hephaestus писал:
09.05.2020 20:32
Я не очень понял, какую именно задачу решает исходный скрипт
К сожалению этот скрипт не работает.
Так как задан оператор начала строки в sed ^, следом за ним идёт оператор конца строки $, и единица после. Другими словами $1 все портит.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20752
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: функция goto

Сообщение Bizdelnick »

ormorph писал(а):
09.05.2020 21:02
Другими словами $1 все портит.
Не портит.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2604
ОС: Gentoo

Re: функция goto

Сообщение ormorph »

Bizdelnick писал:
09.05.2020 21:29
Не портит.
Тогда фиг его знает что она у меня не работает)
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3729
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2
Контактная информация:

Re: функция goto

Сообщение Hephaestus »

ormorph писал(а):
09.05.2020 21:02
К сожалению этот скрипт не работает.
Какой? Однострочник с sed, который я процитировал?
Или тот, который в первом посте?
Но я в любом случае пока не понял, какая именно задача решается.
Логика скрипта из первого поста вроде выглядит так:
файл считывается построчно, если очередная строка совпала с заданной,
то эта строка и последующие выводятся в отдельный файл.
Затрудняюсь рассудить, зачем это надо делать именно таким образом.

Если я верно уловил суть задачи, то данную операцию можно выполнить
например, с помощью grep/head/tail.

И уж совсем мне непонятно, при чем тут goto.
Оператор goto вообще-то работает несколько иначе.

Скрипты я не запускал, поэтому могу ошибаться.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2604
ОС: Gentoo

Re: функция goto

Сообщение ormorph »

Hephaestus писал:
09.05.2020 21:45
Какой? Однострочник с sed, который я процитировал?
Да он самый.
Hephaestus писал:
09.05.2020 21:45
И уж совсем мне непонятно, при чем тут goto.
goto это можно назвать с большой натяжкой, тут просто смысл выполнить последовательность команд начиная с определённой строки, которая задаётся как первый параметр данной функции.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20752
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: функция goto

Сообщение Bizdelnick »

ormorph писал(а):
09.05.2020 21:58
goto это можно назвать с большой натяжкой, тут просто смысл выполнить последовательность команд начиная с определённой строки, которая задаётся как первый параметр данной функции.
И все эти попытки обломаются, если в $0 окажется не полный путь к скрипту, а что-то другое.
Кстати, в конец функции надо добавить exit, ибо если в конце скрипта его не будет, выполнение продолжится дальше с места вызова goto.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 900
ОС: debian, fedora (i3-wm)

Re: функция goto

Сообщение olecya »

Вот такой еще придумала вариант но еще не проверяла

Код: Выделить всё

mapfile -s"$(grep -n "^$1" $0 | cut -d: -f1)" <$0
. <(echo "${MAPFILE[@]}")
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2604
ОС: Gentoo

Re: функция goto

Сообщение ormorph »

Bizdelnick писал:
09.05.2020 22:06
И все эти попытки обломаются, если в $0 окажется не полный путь к скрипту, а что-то другое.
В том то и дело, что путь полный, и у меня не работает.
С этой же конструкцией все правильно выводит:

Код: Выделить всё

sed "1,$(($1-1))d" $0
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 900
ОС: debian, fedora (i3-wm)

Re: функция goto

Сообщение olecya »

Вот это точно должно работать.

Код: Выделить всё

goto() { sed "/^$1"'/,$!d' $0 | bash; }
Добавлено (22:34):
Вот, сумашедший крокодил получился :rolleyes:

Код: Выделить всё

tail -"$(($(wc -l <$0)-$(grep -n "^$1" $0 | cut -d: -f1)))" $0
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2604
ОС: Gentoo

Re: функция goto

Сообщение ormorph »

olecya писала:
09.05.2020 22:27
Вот это точно должно работать.
А пардон, не совсем разобрался в конструкции. Там в качестве метки используется слово а не номер строки. Только тогда задавать точки перехода комментариями и вызывать командой:

Код: Выделить всё

goto \#f:
Двоеточие в конце обязательно в параметре задавать, иначе могут быть проблемы с определением.
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 900
ОС: debian, fedora (i3-wm)

Re: функция goto

Сообщение olecya »

ormorph писал(а):
09.05.2020 22:48
Там в качестве метки используется слово
Нет в качестве метки используется пустая команда с параметром
Но ваш вариант мне кажется практичней
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20752
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: функция goto

Сообщение Bizdelnick »

olecya писала:
09.05.2020 22:27
Вот это точно должно работать.

Код: Выделить всё

goto() { sed "/^$1"'/,$!d' $0 | bash; }
Неа.

Код: Выделить всё

name=olecya
goto ': 1:'
: 1:
echo "hello $name!"
exit
Упс…
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Ответить