Bash goto (как)

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

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

Ответить
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Bash goto

Сообщение flook »

Есть скриптец, который делает (например) следующее

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

# prepare
mkdir A
mknod B
mount B A
# do smth useful
...
# cleanup
umount A
rm -f B
rmdir A

Не спрашивайте зачем я удаляю все опосля - так надо.
Соответственно если какя-то из операций "подготовки" обламывается мне нужно "откатить" все что было сделано выше нее. В C я бы сделал примерно так:

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

 int err = -1;
 if (mkdir(...) == -1)
   goto err_mkdir;
 if (mknod(...) == -1)
  goto err_mknod;
 if (mount(...) == -1)
  goto err_mount;
...
  err = 0;
  umount(...);
err_mount:
  unlink(...);
err_mknod;
  rmdir(...);
err_mkdir:
 return err;

Вопрос - как сделать похожее в bash?
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
madskull
Сообщения: 1019
Статус: Экс-металлюга
Контактная информация:

Re: Bash goto

Сообщение madskull »

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

if mkdir A; then
    if mknod B; then
        if mount B A; then
            do_smth
            umount A
        fi
        rm -f B
    fi
    rmdir A
fi  


И в сях ты не очень :)
Я далеко не гото-ненавистник, но так издеваться над логикой программы...
ArchLinux / IceWM
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(madskull @ Среда, 29 Июня 2005, 16:25) писал(а):

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

if mkdir A; then
    if mknod B; then
        if mount B A; then
            do_smth
            umount A
        fi  
        rm -f B
    fi  
    rmdir A
fi  

ОК. А если подготовительных операций 30?

(madskull @ Среда, 29 Июня 2005, 16:25) писал(а):И в сях ты не очень :)
Я далеко не гото-ненавистник, но так издеваться над логикой программы...

Предложите более красивый способ порулить такую ситуацию в C.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
madskull
Сообщения: 1019
Статус: Экс-металлюга
Контактная информация:

Re: Bash goto

Сообщение madskull »

(flook @ Среда, 29 Июня 2005, 16:50) писал(а):ОК. А если подготовительных операций 30?

Наверное, делать 30 вложенных if-ов. А вообще надо знать, что хочется. От этого и плясать.

(flook @ Среда, 29 Июня 2005, 16:50) писал(а):Предложите более красивый способ порулить такую ситуацию в C.

Так же, как и в приведенном примере :)
ArchLinux / IceWM
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(madskull @ Среда, 29 Июня 2005, 16:55) писал(а):
(flook @ Среда, 29 Июня 2005, 16:50) писал(а):ОК. А если подготовительных операций 30?

Наверное, делать 30 вложенных if-ов. А вообще надо знать, что хочется. От этого и плясать.

Это сильно портит внешний вид программы...
Нужно сделать ровно то, что я написал: mknod, mkdir, mount ... umount, rmdir, unlink.
Предложенный способ сильно криво выглядит в коде.
Если нужна конкретика где больше 3х подготовительный шагов то я могу и их привести.

(madskull @ Среда, 29 Июня 2005, 16:55) писал(а):
(flook @ Среда, 29 Июня 2005, 16:50) писал(а):Предложите более красивый способ порулить такую ситуацию в C.

Так же, как и в приведенном примере :)


Это криво. Что делать в случае 30 операций? Мой способ выглядит одинаково и там и там, а с тучей if-ов код за край экрана ой как быстро выползет.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
madskull
Сообщения: 1019
Статус: Экс-металлюга
Контактная информация:

Re: Bash goto

Сообщение madskull »

Спорить не буду. На вкус и цвет все фломастеры разные.

Но в твоем примере рябит в глазах (в моих) от if'ов, goto'ов и названий меток. ИМХО

madskull добавил в 29.06.2005 18:29

Короче, нет в баше goto :)
ArchLinux / IceWM
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(madskull @ Среда, 29 Июня 2005, 17:29) писал(а):Спорить не буду. На вкус и цвет все фломастеры разные.

Но в твоем примере рябит в глазах (в моих) от if'ов, goto'ов и названий меток. ИМХО

А по-другому очень часто никак. Как бы Вы оформили вот такой код?

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

static inline int do_rename(const char * oldname, const char * newname)
{
        int error = 0;
        struct dentry * old_dir, * new_dir;
        struct dentry * old_dentry, *new_dentry;
        struct dentry * trap;
        struct nameidata oldnd, newnd;

        error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
        if (error)
                goto exit;

        error = path_lookup(newname, LOOKUP_PARENT, &newnd);
        if (error)
                goto exit1;

        error = -EXDEV;
        if (oldnd.mnt != newnd.mnt)
                goto exit2;

        old_dir = oldnd.dentry;
        error = -EBUSY;
        if (oldnd.last_type != LAST_NORM)
                goto exit2;

        new_dir = newnd.dentry;
        if (newnd.last_type != LAST_NORM)
                goto exit2;

        trap = lock_rename(new_dir, old_dir);

        old_dentry = lookup_hash(&oldnd.last, old_dir);
        error = PTR_ERR(old_dentry);
        if (IS_ERR(old_dentry))
                goto exit3;
        /* source must exist */
        error = -ENOENT;
        if (!old_dentry->d_inode)
                goto exit4;
        /* unless the source is a directory trailing slashes give -ENOTDIR */
        if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
                error = -ENOTDIR;
                if (oldnd.last.name[oldnd.last.len])
                        goto exit4;
                if (newnd.last.name[newnd.last.len])
                        goto exit4;
        }
        /* source should not be ancestor of target */
        error = -EINVAL;
        if (old_dentry == trap)
                goto exit4;
        new_dentry = lookup_hash(&newnd.last, new_dir);
        error = PTR_ERR(new_dentry);
        if (IS_ERR(new_dentry))
                goto exit4;
        /* target should not be an ancestor of source */
        error = -ENOTEMPTY;
        if (new_dentry == trap)
                goto exit5;

        error = vfs_rename(old_dir->d_inode, old_dentry,
                                   new_dir->d_inode, new_dentry);
exit5:
        dput(new_dentry);
exit4:
        dput(old_dentry);
exit3:
        unlock_rename(new_dir, old_dir);
exit2:
        path_release(&newnd);
exit1:
        path_release(&oldnd);
exit:
        return error;
}

Это функция ядра по переименовыванию файлов. Важно при обломе откатить все предыдущее. Или поглядите на copy_process из файла kernel/fork.c - там еще круче.

(madskull @ Среда, 29 Июня 2005, 17:29) писал(а):Короче, нет в баше goto :)

Так бы сразу :) А то какие-то заменители предлагать стали.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
KiWi
Бывший модератор
Сообщения: 2521
Статус: статус, статус, статус
Контактная информация:

Re: Bash goto

Сообщение KiWi »

так, switch'а в баше тоже нет, тогда такой вариант-заменитель - функция, аргументом которой является число - стадия, а в функции
если (число >= 1) удалить файл
если (число >= 2) удалить директорию
и т.д.
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(mani13 @ Среда, 29 Июня 2005, 18:06) писал(а):так, switch'а в баше тоже нет, тогда такой вариант-заменитель - функция, аргументом которой является число - стадия, а в функции
если (число >= 1) удалить файл
если (число >= 2) удалить директорию
и т.д.

Не надо ля-ля :) switch есть. Посмотрите любой startup скрипт из /etc.init.d

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

case "$1" in
   start)
    do_start;
   ;;
   stop)
    do_stop;
   ;;;
esac
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
madskull
Сообщения: 1019
Статус: Экс-металлюга
Контактная информация:

Re: Bash goto

Сообщение madskull »

(flook @ Среда, 29 Июня 2005, 17:39) писал(а):А по-другому очень часто никак. Как бы Вы оформили вот такой код?
--- скип ---
Это функция ядра по переименовыванию файлов. Важно при обломе откатить все предыдущее. Или поглядите на copy_process из файла kernel/fork.c - там еще круче.


Так я же говорю: я не против использования goto, где это необходимо.
Но в самом первом сишном примере можно было обойтись без него, читаемость кода была бы выше.
ArchLinux / IceWM
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(madskull @ Среда, 29 Июня 2005, 18:17) писал(а):Так я же говорю: я не против использования goto, где это необходимо.
Но в самом первом сишном примере можно было обойтись без него, читаемость кода была бы выше.

Не выше :) Мой (хоть может и небогатый) опыт подсказывает, что если везде (даже на 1 подготовительную операцию) писать так, а не иначе, потом гораздо меньше сил тратится на втыкание, расширение и поиск BUGов.

Кстати в bash жалким подобием стала такая монструозная конструкция

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

function rolabak_1()
{
  exit 1;
}

function rollback_2()
{
   rm -f A
   rolbask_1()
}

с вызовами типа

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

mknod A || rollabsk_1;
mkdir B || rollbask_2();

Фуф... Ужас.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
KiWi
Бывший модератор
Сообщения: 2521
Статус: статус, статус, статус
Контактная информация:

Re: Bash goto

Сообщение KiWi »

flook, мдаааааааа........ там 1 функцией с параметром это делается (:


p.s.: хм, только в 5 скриптах из init.d нашёл case (:
p.p.s.: похоже здесь всё-таки нет аналога такого switch'а:

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

switch(var){
case 2: printf("%s", "Str2\n");
case 1: printf("%s", "Str1\n");
}

то есть, чтобы при var=2 вывелось:

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

Str2
Str1
Спасибо сказали:
Аватара пользователя
madskull
Сообщения: 1019
Статус: Экс-металлюга
Контактная информация:

Re: Bash goto

Сообщение madskull »

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

case $var in
  1) echo "Str1";;
  2) echo "Str2";;
esac

Что не так?
ArchLinux / IceWM
Спасибо сказали:
Аватара пользователя
bolt
Сообщения: 47

Re: Bash goto

Сообщение bolt »

Для flook:
Имхо, лучше не увлекай goto. Тут действует правило: чем меньше, тем лучше. И насчет багов ты тоже не прав. Отыскивать их как раз с goto на порядок тяжелее ( конечно, это зависит насколь юлиные прыжки и от их кол-ва )
Кстати насчет исходнико ядра: ты не сравнивай это дело, т.к. там goto используется для оптимизации кода. Там написано в стиле ассемблера в C-синтаксисе.
GNU/Linux...
...made by Hackers for Freedom...
Freedom forever!
Спасибо сказали:
Аватара пользователя
KiWi
Бывший модератор
Сообщения: 2521
Статус: статус, статус, статус
Контактная информация:

Re: Bash goto

Сообщение KiWi »

(madskull @ Среда, 29 Июня 2005, 19:57) писал(а):

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

case $var in
  1) echo "Str1";;
  2) echo "Str2";;
esac

Что не так?

не так то, что при значениях var=1 и var=2 выведутся только Str1 и Str2 соответственно...
то есть после ;; будет выход из case... в СИ без break; он пойдёт дальше до брейка, а не выйдет перед следующим кейсом
Спасибо сказали:
Аватара пользователя
madskull
Сообщения: 1019
Статус: Экс-металлюга
Контактная информация:

Re: Bash goto

Сообщение madskull »

А, да. Это точно. К сожалению.
ArchLinux / IceWM
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(bolt @ Среда, 29 Июня 2005, 20:07) писал(а):Для flook:
Имхо, лучше не увлекай goto. Тут действует правило: чем меньше, тем лучше. И насчет багов ты тоже не прав.

Еще как прав. Большое кол-во goto при дизассемблировании превращается в довольно симпатишный код, который выглядит примерно так

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

cmp X1, Y1
je Z1
cmp X2, Y2
jae Z2

и когда случается BUG или Oops то такой код отследить и сопоставить с Cшным гораздо проще чем то, что получается без goto. Практически всегда.

(bolt @ Среда, 29 Июня 2005, 20:07) писал(а):Отыскивать их как раз с goto на порядок тяжелее ( конечно, это зависит насколь юлиные прыжки и от их кол-ва )
Кстати насчет исходнико ядра: ты не сравнивай это дело, т.к. там goto используется для оптимизации кода. Там написано в стиле ассемблера в C-синтаксисе.

Там для оптимизации кода используется не только goto и кода используется НЕ goto следить по asm коду за C кодом становится делом слишком тяжким...

Я тоже сначала был "goto-purist-ом", а потом, когда год провозился с ядром, посмотрел на этот код мне и в user_space стало проще писать за счет использования "ядерных шаблонов"...

Кстати еще один плюс в использовании "рекламируемых" :P мною конструкция заключается в следующем. Когда в программе туча вложенныи if, while, switch и иже с ними из-за использования indentation в 8 символов код оччень быстро сползает вправо и в консоли (25Х80) его не прочтешь... А такой indent и 25X80 - стандарт кода ядра прописаный в KernelCodingStyle не придерживаясь которого нет никаких шансов что твой код хотябы посмотрят хлопцы из torvalds'n'co.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: Bash goto

Сообщение t.t »

(flook @ Среда, 29 Июня 2005, 18:22) писал(а):Фуф... Ужас.
А почему бы не так, скажем?

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

mkdir A || exit 1
mknod B || (rmdir A; exit 1)
mount B A || (rm -f B; rmdir A; exit 1)

И не надо никаких функций...
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(t.t @ Пятница, 01 Июля 2005, 18:52) писал(а):
(flook @ Среда, 29 Июня 2005, 18:22) писал(а):Фуф... Ужас.
А почему бы не так, скажем?

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

mkdir A || exit 1
mknod B || (rmdir A; exit 1)
mount B A || (rm -f B; rmdir A; exit 1)

И не надо никаких функций...


У этого подхода по моему мнению 2 недостатка:
1. Дубляж кода (вместо rmdir и rm -f могут стоять другие, более длинные действия);
2. Совсем не катит для (как я уже говорил) большого количества шагов подготовки и отката.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
bolt
Сообщения: 47

Re: Bash goto

Сообщение bolt »

Для flook:
и когда случается BUG или Oops то такой код отследить и сопоставить с Cшным гораздо проще чем то, что получается без goto. Практически всегда.

Я же сказал, что такой подход приемлем тольк для низкоуровневого программирования ( например ядро ). Ты что будешь писать, например оболочку для базы данных, и если у тебя будет ошибка, ты дизассемблируешь программу, потом будешь искать баг в листинге ассемблера? :lol: Подход с goto не приемлем к большим программам написанным на высокоуровневом языке.
Тебе совет: почитай вот эту книжку http://prog.dax.ru/docs/cpprules/
GNU/Linux...
...made by Hackers for Freedom...
Freedom forever!
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Bash goto

Сообщение flook »

(bolt @ Суббота, 02 Июля 2005, 13:03) писал(а):Для flook:
и когда случается BUG или Oops то такой код отследить и сопоставить с Cшным гораздо проще чем то, что получается без goto. Практически всегда.

Я же сказал, что такой подход приемлем тольк для низкоуровневого программирования ( например ядро ). Ты что будешь писать, например оболочку для базы данных, и если у тебя будет ошибка, ты дизассемблируешь программу, потом будешь искать баг в листинге ассемблера? :lol: Подход с goto не приемлем к большим программам написанным на высокоуровневом языке.
Тебе совет: почитай вот эту книжку http://prog.dax.ru/docs/cpprules/


Talk is cheap, show me the code (Torvalds ©).
Я предпочитаю читать не книги, а код, преимущественно ядерный :P Как показала практика, такой способ эффективнее.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: Bash goto

Сообщение t.t »

(flook @ Суббота, 02 Июля 2005, 9:26) писал(а):У этого подхода по моему мнению 2 недостатка:
1. Дубляж кода (вместо rmdir и rm -f могут стоять другие, более длинные действия);
2. Совсем не катит для (как я уже говорил) большого количества шагов подготовки и отката.
Это да, но exit уж во всяком случае не стоило в функцию заворачитвать.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Ответить