Пятничная загогулина (bash)
Ну вот, пришло время для очередной программерской загогулины. Следующий код работать не будет:
#!/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>"

есть мнение, что переменные, прочитанные read, остаются в переменных “экземпляра” баша, запущенного для выполнения “read a b c”, и не попадают в родительский баш, запустивший “echo … | read a b c”.
gds, эмм. Да, вероятней всего так оно и есть.
Я уже думаю, что слишком простая задачка..
Спасибо за ответ! :)
gds в чем-то прав
echo one two three| (read a b c ; echo "< $a>< $b>< $c>")Даже не в чем-то, а полностью прав:
Each command in a pipeline is executed as a separate process (i.e., in a subshell).
bappoy, команда, написанная тобой – комментарий к сказанному г-ном gds?
Если да, то я полностью согласен, если нет – то это не работает (пишу это, чтобы никто не подумал, что решение уже найдено :)
UPD: я понял, что этот сволочной wordpress подточил вывод переменных в echo. Исправил форму и подправил код в комментах.
а вот с первым вопросом непонятки.
как вариант — 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
но это ещё кривее.
Будет очень интересно посмотреть на нормальное решение; возможно, не прямо сейчас, а когда угадают.
read a b c < `echo “one too free”`
не подойдет?
gds, ага, кривовато.
Nicka, не, у меня не пашет.
Готово!
str=`echo "one two three" | (read a b c; echo "a=$a; b=$b; c=$c;") `eval "$str";
echo "< $a> < $b> < $c>"
Имхо, правильное решение – не использовать bash. Он ни лучший, ни универсальный. Например, sh и zsh – обрабатывают сию ситуацию, как и ожидается.
gemelen, а пример можно?
На самом деле, это вполне адекватная реакция баша. Важно просто правильно понимать его логику работы.
Ага, это here string называется
читать, читать, читать man bash до окончательного просветления
Очень интересный блог, с удовольствием подписываюсь :)
(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.
Павел, вы абсолютно правы, ‘echo’ и обратные кавычки не обязательны, в данном случае обработка `echo “one two three”` – это просто часть исходной задачи.
А в задаче они появились, потому что с проблемой я столкнулся, пытаясь обработать вывод внешней программы.
Так-то! :)