LINUX.ORG.RU

Чтение значения переменной из файла в shell-скрипте

 , , , ,


2

4

Из серии «я познаю мир».

Ковыряясь в инит-скриптах замшелого Линукса, установленного на моём NAS, встретил следующую строку

read line <"$pid_file"

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

line=$(cat "$pid_file")

выглядит куда нагляднее (не то, что башизм $(<"$pid_file")). Но, приведя пульс в порядок и отогнав приступ праведного гнева, я стал размышлять над этой строчкой:

  • не порождаются суб-шелл и cat (минус два форка)
  • читается почти как well-written prose (если не считать косяк в виде имени line для переменной, содержащей pid)
  • надо брать на вооружение

Беглый анализ показывает, что в современном Дебиане оба подхода примерно одинаково популярны:

$ grep '=$(cat [^)]*)' -r /etc/ 2>/dev/null | wc -l
10
$ egrep 'read [[:alpha:]_][[:alnum:]_]*[[:blank:]]*<' -r /etc/ 2>/dev/null | wc -l
7

Что скажут ценители?

Ну, и для развлечения тест производительности :-)

Классика:

$ cat cat_test.sh
#!/bin/sh

i=0

while [ $i -lt $1 ]; do
    var=$(cat value)
    i=$(($i+1))
done

echo $var

Башизм:

$ cat bashcat_test.sh 
#!/bin/bash

i=0

while [ $i -lt $1 ]; do
    var=$(< value)
    i=$(($i+1))
done

echo $var

read:

$ cat read_test.sh
#!/bin/sh

i=0

while [ $i -lt $1 ]; do
    read var < value
    i=$(($i+1))
done

echo $var

Результаты:

$ echo this is a value > value
$ time ./cat_test.sh 1000
this is a value

real    0m2.129s
user    0m0.056s
sys     0m0.212s
$ time ./bashcat_test.sh 1000
this is a value

real    0m0.777s
user    0m0.108s
sys     0m0.144s

$ time ./read_test.sh 1000
this is a value

real    0m0.036s
user    0m0.000s
sys     0m0.036s

Смысл мерить производительность? Если скрипт упирается в скорость чтения переменной из файла, то возможно инструмент выбран не очень удачно.

anonymous ()

на с с файлом в tmpfs будет ещё быстрее /thread

anonymous ()

А зачем здесь while?

TGZ ★★★★ ()

Интересненько. Возьму на заметку, спасибо.

sT331h0rs3 ★★★★★ ()

OMG, Капитан Очевидность

Epic battle: builtin VS external programs.

Who won?

anonymous ()
Ответ на: комментарий от anonymous

на с с файлом в tmpfs будет ещё быстрее /thread

уверен? у меня для тебя плохие новости.

emulek ()

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

ты забыл тег «я познаю мир».

и да, я об этом уже Over9000 здесь говорил: не знаешь ЯП, не проводи тесты. Это смешно и грустно.

emulek ()
Последнее исправление: emulek (всего исправлений: 1)

i=$(($i+1))

facepalm

((i++))

if [ $i -lt $1 ]

говнокод в каждой строке if ((i<$1))

emulek ()
Последнее исправление: emulek (всего исправлений: 1)
Ответ на: комментарий от emulek

ты забыл тег «я познаю мир»

Что же тогда ты видишь в первой строчке моего поста?!

unterwulf ()
Ответ на: комментарий от emulek

Каюсь, с башем и его башизмами работаю только в read-only режиме, а православный posix-шелл таких конструкций не позволяет. Но здесь это роли не играет, т.к. интересно сравнение именно только одной операции. Адаптация скрипта к рюшечкам баша сделала бы сравнение менее честным.

А вообще жаль, что основное внимание общественности привлекло несчастное сравнение производительности, добавленное мною для забавы.

Я хотел почитать мнения людей о выразительности этой конструкции, а не о её производительности.

unterwulf ()
Ответ на: комментарий от TGZ

А зачем здесь while?

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

unterwulf ()
Ответ на: комментарий от unterwulf

Видишь ли, дело в том, что ты сравниваешь отнюдь не эквивалентные конструкции.
Подсказка: что будет, если файл случайно окажется Большой Советской Энциклопедией - все 50+ томов в rtf?

ABW ★★★★ ()
Ответ на: комментарий от ABW

Видишь ли, дело в том, что ты сравниваешь отнюдь не эквивалентные конструкции.

Они не эквивалентные, но они обе способны решать простую задачу — считать строковое значение переменной из файла (согласен, в первом посте это не было обозначено достаточно явно). Понятно, что read не считает более одной строки. Сама эта задача и есть предмет обсуждения. Конструкции я сравниваю только в её контексте.

unterwulf ()
Ответ на: комментарий от unterwulf

Я просто перепутал «$1» с «1», вот и подумал нафига while на один проход.

TGZ ★★★★ ()
Последнее исправление: TGZ (всего исправлений: 1)
Ответ на: комментарий от unterwulf

Как можно говорить за выразительность с тем, кто не разумеет используемый язык?

emulek ()
Ответ на: комментарий от emulek

И да, твоя cat здесь лишняя сущность, как как у собаки пятый пенис.

emulek ()
Ответ на: комментарий от emulek

не разумеет используемый язык

Поясни, откуда такой вывод.

unterwulf ()
Ответ на: комментарий от emulek

твоя cat здесь лишняя сущность

Объясни это мэйнтейнерам Дебиана. Или пост таки не читал?

unterwulf ()
Ответ на: комментарий от unterwulf

Сам-то читал? Тс как раз и недоумевает, что нет кошки, которая на его взгляд «логичная».

emulek ()
Ответ на: комментарий от unterwulf

Задача: прочитать файл в переменную. Команда read(1) делает именно это. Всё остальное — костыли. Например кошка в субшеле.

emulek ()

Ценители одобряют.

Наркомана емуколека в игнорь кинь.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.