Home > SHELL, UNIX, Программирование, загогулины > Пятничная загогулина (bash)

Пятничная загогулина (bash)

April 11th, 2008 Leave a comment Go to comments

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

#!/usr/bin/bash
echo "one two three" | read a b c
echo "<$a> <$b> <$c>"

Что в нем не так?

Я ожидаю увидеть два ответа. Первый — это просто переписать этот код так, чтобы он заработал. И второй ответ — опционально — объяснение, почему не работает в таком виде.

p.s. второго ответа я пока сам не знаю, поэтому буду с интересом ждать его от вас :)
p.p.s. ответивший верно, как всегда – умничка (-ца (маловероятно)).

UPD: На второй вопрос ответ уже есть:
gds
есть мнение, что переменные, прочитанные read, остаются в переменных “экземпляра” баша, запущенного для выполнения “read a b c”, и не попадают в родительский баш, запустивший “echo … | read a b c”.

gds’у – респект!
А я понял, что в следующий раз надо постить задачки посложнее..

UPD2 свое решение выложу сегодня в конце рабочего дня
UPD3

Кажется, я нечаянно сорвал рабочий день моего начальника, но зато он мне прислал вот такое остроумное решение:
str=`echo "one two three" | (read a b c; echo "a=$a; b=$b; c=$c;") `
eval "$str";
echo "<$a> <$b> <$c>"

Петя, ты отжог :)

Но на самом деле все это можно сделать несколько проще – через “here doc”:
read a b c <<<`echo "one two three"`
echo "<$a> <$b> <$c>"

  1. gds
    April 11th, 2008 at 13:58 | #1

    есть мнение, что переменные, прочитанные read, остаются в переменных “экземпляра” баша, запущенного для выполнения “read a b c”, и не попадают в родительский баш, запустивший “echo … | read a b c”.

  2. Alexey Sveshnikov
    April 11th, 2008 at 14:01 | #2

    gds, эмм. Да, вероятней всего так оно и есть.

    Я уже думаю, что слишком простая задачка..

    Спасибо за ответ! :)

  3. April 11th, 2008 at 14:05 | #3

    gds в чем-то прав

    echo one two three| (read a b c ; echo "< $a>< $b>< $c>")

  4. April 11th, 2008 at 14:08 | #4

    Даже не в чем-то, а полностью прав:

    Each command in a pipeline is executed as a separate process (i.e., in a subshell).

  5. Alexey Sveshnikov
    April 11th, 2008 at 14:12 | #5

    bappoy, команда, написанная тобой – комментарий к сказанному г-ном gds?
    Если да, то я полностью согласен, если нет – то это не работает (пишу это, чтобы никто не подумал, что решение уже найдено :)

    UPD: я понял, что этот сволочной wordpress подточил вывод переменных в echo. Исправил форму и подправил код в комментах.

  6. gds
    April 11th, 2008 at 14:24 | #6

    а вот с первым вопросом непонятки.
    как вариант — continuation-passing style:

    $ echo one two three | ( read a b c ;
    echo "< $a>< $b>< $c>"
    )

    но кривовато.

    Можно через создание временного файла:

    echo one two three > /tmp/somefile ; read a b c < /tmp/somefile

    но это ещё кривее.

    Будет очень интересно посмотреть на нормальное решение; возможно, не прямо сейчас, а когда угадают.

  7. April 11th, 2008 at 14:30 | #7

    read a b c < `echo “one too free”`
    не подойдет?

  8. Alexey Sveshnikov
    April 11th, 2008 at 15:41 | #8

    gds, ага, кривовато.
    Nicka, не, у меня не пашет.

  9. April 11th, 2008 at 16:19 | #9

    Готово!
    str=`echo "one two three" | (read a b c; echo "a=$a; b=$b; c=$c;") `
    eval "$str";
    echo "< $a> < $b> < $c>"

  10. gemelen
    April 11th, 2008 at 18:04 | #10

    Имхо, правильное решение – не использовать bash. Он ни лучший, ни универсальный. Например, sh и zsh – обрабатывают сию ситуацию, как и ожидается.

  11. Alexey Sveshnikov
    April 11th, 2008 at 18:12 | #11

    gemelen, а пример можно?

    На самом деле, это вполне адекватная реакция баша. Важно просто правильно понимать его логику работы.

  12. April 11th, 2008 at 21:19 | #12

    Ага, это here string называется
    читать, читать, читать man bash до окончательного просветления

  13. December 13th, 2009 at 18:43 | #13

    Очень интересный блог, с удовольствием подписываюсь :)

  14. January 6th, 2010 at 13:55 | #14

    (excuse me, I read Russian well, but I can’t write in it)

    About:
    read a b c <<<`echo "one two three"`

    What's the point in `echo "one two three"`? Why not just be like this:
    read a b c <<<one two three

    I mean, `echo "one two three"` produces one two three and they're essentially the same thing.

  15. Alexey Sveshnikov
    January 15th, 2010 at 03:46 | #15

    Павел, вы абсолютно правы, ‘echo’ и обратные кавычки не обязательны, в данном случае обработка `echo “one two three”` – это просто часть исходной задачи.

    А в задаче они появились, потому что с проблемой я столкнулся, пытаясь обработать вывод внешней программы.

    Так-то! :)

  1. No trackbacks yet.