ksh93
має дисципліни, які зазвичай використовуються для подібних речей. З zsh
, ви можете викрасти динамічну функцію з ім'ям каталогу :
Визначте, наприклад:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
І тоді ви можете використовувати, ~[incr]
щоб отримувати збільшення $incr
кожного разу:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Ваш підхід не вдається, тому що в head -1 /tmp/ints
голові відкривається фіфо, читається повний буфер, друкується один рядок, а потім закривається . Після закриття пишучий кінець бачить розбиту трубу.
Натомість ви можете:
$ fifo=~/.generators/incr
$ (umask 077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ seq infinity > $fifo &
$ exec 3< $fifo
$ IFS= read -rneu3
1
$ IFS= read -rneu3
2
Там ми залишаємо кінець читання відкритим на fd 3 і read
читаємо по одному байту, а не повний буфер, щоб переконатися, що він читає рівно один рядок (до символу нового рядка).
Або ви могли б зробити:
$ fifo=~/.generators/incr
$ (umask 077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ while true; do echo $((++incr)) > $fifo; done &
$ cat $fifo
1
$ cat $fifo
2
У цей час ми створюємо трубу для кожної цінності. Це дозволяє повертати дані, що містять будь-яку довільну кількість рядків.
Однак у цьому випадку, як тільки cat
відкривається фіфа, echo
цикл і цикл розблоковуються, тому echo
можна буде запустити більше, до моменту cat
зчитування вмісту та закриття каналу (внаслідок чого наступна echo
інстанціює нову трубку).
echo
Заохоченням може бути додавання деякої затримки, як, наприклад, запуск зовнішнього, як запропонував @jimmij, або додавання деяких sleep
, але це все одно не буде дуже надійним, або ви можете відтворити названу трубу після кожного echo
:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Це все ще залишає короткі вікна, де труба не існує (між unlink()
виконаним rm
і mknod()
зробленим mkfifo
), що призводить cat
до виходу з ладу, і дуже короткі вікна, де труба була створена, але жоден процес ніколи не запишеться до неї (між write()
і close()
зроблено шляхом echo
), що cat
не повертає нічого, і короткі вікна, де названа труба все ще існує, але нічого ніколи не відкриє її для написання (між close()
виконаним echo
і unlink()
виконаним rm
), де cat
буде висіти.
Ви можете видалити деякі з цих вікон , зробивши це так:
fifo=~/.generators/incr
(
umask 077
mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo &&
while
mkfifo $fifo.new &&
{
mv $fifo.new $fifo &&
echo $((++incr))
} > $fifo
do : nothing
done
) &
Таким чином, єдина проблема полягає в тому, якщо ви запускаєте декілька котів одночасно (всі вони відкривають фіфо, перш ніж наша петля для письма буде готова відкрити її для запису), і в цьому випадку вони поділять echo
результат.
Я б також радив не створювати фіксовану назву, доступний для читання у світі фіфос (або будь-який файл для цього) у світових каталогах, що записуються, наприклад, /tmp
якщо це не сервіс, який піддається впливу всіх користувачів системи.