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якщо це не сервіс, який піддається впливу всіх користувачів системи.