LINUX.ORG.RU

Оптимизация bash скрипта.

 ,


0

1

Есть такая задачка:

Напишите сценарий, который выводит дату, время, список зарегистрировавшихся пользователей, и uptime системы и сохраняет эту информацию в системном журнале.

Собственно ниже решение:


#!/bin/bash

log_dir=/var/log

date
who
uptime
cd $log_dir

if [ "$PWD" = "$log_dir" ]
then
 date >> messages
 who >> messages
 uptime >> messages
 echo " "
else
 echo "Необходима магия"
fi

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


logger «Hello, $USER»

anonymous
()

Блевать здесь тянет не от троекратного перенаправления, единственная проблема которого — повторение строкового литерала, а от того, что вы самым грязным образом что-то пишете в /var/log/messages. Как справедливо отметил аноним, см. logger(1).

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

date
date >> messages

Вот это тоже то, от чего (в отличие от перенаправления) может потянуть. Можно сказать: «Переменные? Не, не слышал».

date=$(date)
printf '%s\n' "$date"
printf '%s\n' "$date" >> some-file

И кстати, в ГНУ Баше нет необходимости в вызове внешней программы для получения текущего времени и даты.

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

Такого файла у меня вообще не было, руками создал.

Еще лучше. Что вы вообще пытаетесь сделать? Загадить систему? Какая она у вас, кстати?

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

И кстати, в ГНУ Баше нет необходимости в вызове внешней программы для получения текущего времени и даты.

Всм? Подробности пожалуйста

gats
() автор топика

cd $log_dir
if [ "$PWD" = "$log_dir" ]

Еще один весьма стремный момент. Если вы так будете описывать логику в настоящих программах, у вас никакой ширины экрана не хватит. goto в Баше нет, так что если полное завершение программы (exit) по смыслу не катит, выделяйте подпрограмму (функцию).

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

Всм?

Что, пардон?

Подробности пожалуйста

printf.

Zmicier ★★★★★
()

echo "Необходима магия"

Вот еще один косяк. Если это сообщение об ошибке, то на стандартном выводе ему делать нечего, для него существует (сюрприз!) вывод ошибок. И да, некорректно отработавшая программа не должна возвращать успешный (нулевой) код.

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

Вот еще один косяк. Если это сообщение об ошибке, то на стандартном выводе ему делать нечего, для него существует (сюрприз!) вывод ошибок.

Или не знал об exit?

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

Или не знал об exit?

Что?

Если непонятно, о чем я толкую, то о том, что целесообразно писать как-то так:

err ()
{
    printf '%s\n' >&2 "$*"
    exit 1
}

cd "$dir" || err $"We need magic"
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

При чем тут это. Вопрос был о фразе:

И кстати, в ГНУ Баше нет необходимости в вызове внешней программы для получения текущего времени и даты.

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

При чем тут это.

Как это «при чем»? Что мы здесь с вами вообще делаем?

Вопрос был о фразе:

Какой вопрос?

«И кстати, в ГНУ Баше нет необходимости в вызове внешней программы для получения текущего времени и даты»

Так вы прочитали, как это сделать при помощи printf?

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

Обсуждаем как оптимизировать приложенный код и как его «целесообразно писать» да. Но обсуждение ушло в другое другое русло.

Вами был дан код как пример

date=$(date)
printf '%s\n' «$date»
printf '%s\n' «$date» >> some-file

После вы добавили, что:

И кстати, в ГНУ Баше нет необходимости в вызове внешней программы для получения текущего времени и даты

Вот я пытаюсь понять, как связан пояснительный код и эта фраза.

Смысл printf я увидел, спасибо.

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

Вот я пытаюсь понять, как связан пояснительный код и эта фраза.

Первое — общий пример. Второе — частное замечание.

Смысл printf я увидел, спасибо.

Где́ вы его увидели? Я говорю, что printf’ом можно запросить текущую дату и время. Неужели даже здесь придется за вас в справочник смотреть?

$ printf -v date '%(%a %b %d %T %Z %Y)T' 
$ printf '%s\n' "$date"
Thu Sep 15 07:01:49 MSK 2016
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Смысл в лаконичности как минимум.

Ну раз можно, то хорошо.

gats
() автор топика

По-моему, Zmicer и есть тот самый учитель, который задал тебе это задание.

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

На деле он пришиблен zsh'ом, но т.к. он (zsh) никому не нужен, пришлось переквалифицироваться в управдома башевода

futurama ★★★★★
()

До вывода сделайте

exec 3<&1 1>>"$targetFile"

После:

exec 1<&3

Коль скоро это BASH, нужно писать не

if [ "$PWD" = "$log_dir" ]

но:

if [[ $PWD == $log_dir ]]

И зачем это вообще нужно? Если есть подозрение, что cd почему-либо не перейдёт в целевой каталог (кстати, зачем туда переходить, нельзя разве писать сразу в файл по его полному пути?) - проверяйте код возврата команды cd:

if cd "$targetPath"; then

Если не нужна интерполяция переменных и команд внутри строки - используйте одинарные кавычки, а не двойные (это меньше напрягает интерпретатор и гарантирует отсутствие ложных интерполяций для строк в духе «This `useful thing` costs 5$!»)

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

Ну-ну, назовите-ка признаки «уродства» того же BASH. Что, говно-ООП нет? Аргумент только для тупых и больных на голову. Следующий!

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

По мне, нет ничего зазорного в том, чтобы сделать просто date +'%Y-%m-%d %H:%M:%S'

ИМХО прежде, чем говорить, что один вариант лучше другого нужно хотя бы тесты какие-то провести. По меньшей мере код с date выглядит понятнее.

DRVTiny ★★★★★
()

Ты вызываешь date, who и uptime дважды. Теоретически между первым и вторым вызовом время и аптайм уже могут измениться, соответственно, на экран и в лог попадут разные значения. К тому же это просто дублирование кода и вызов команд (тут они лёгкие совсем, но в теории могли бы быть тяжёлые) дважды, когда результат нужен один раз. Поэтому целесообразно будет вызвать это дело один раз, результат присвоить переменной, а потом уже эту переменную вывести куда надо. Как-то например так:

#!/bin/sh
log_dir=/var/log
data="$(date;who;uptime)"
echo $data
if cd "$log_dir"; then
  echo $data >> messages
else
  echo "Необходима магия" 1>&2
  exit 1
fi

Далее, тебе в принципе не надо переходить в /var/log. Если надо писать в файл /var/log/messages, то можно в него просто сразу писать. Таким образом выходит всё проще и на 5 строк:

#!/bin/sh
logfile=/var/log/messages
data="$(date;who;uptime)"
echo $data
echo $data >> "$logfile" || (echo "Необходима магия" 1>&2 && exit 1)

Psych218 ★★★★★
()
Последнее исправление: Psych218 (всего исправлений: 2)
Ответ на: комментарий от DRVTiny

if cd "$targetPath"; then

Рискну повторить: «Если вы так будете описывать логику в настоящих программах, у вас никакой ширины экрана не хватит». Да и отрыв сообщения об ошибке от того, что ее порождает, понятности программе не добавляет.

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

data="$(date;who;uptime)"
echo $data
echo $data >> "$logfile" || (echo "Необходима магия" 1>&2 && exit 1)

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

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

Речь шла о том, как лучше написать оператор «if», а не о том, как в принципе нужно правильно писать программы.

Вы как-то забыли ведь упомянуть о том, что переход в каталог + append в файл требует более высоких прав доступа в Unix, нежели просто append в файл?

Так давайте же обсудим всё, начиная с логики системных вызовов, GDT, LDT, IDT и прочие важные сущности! Примерно через 5 лет осилим базовый курс Бауманки по программированию - а там, глядишь, топикстартер вообще переключится на программирование робототехники и перестанет заглядывать в тред.

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

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

Можно узнать, где конкретно ошибки? Только что протестировал (правда в zsh) — всё сработало верно. В обычном sh не сохраняются переносы строк, надо $data взять в кавычки. Но это одна ошибка. Где ещё две?

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

В обычном sh не сохраняются переносы строк, надо $data взять в кавычки.

В ГНУ Баше тоже; а подстановки и zsh раскроются, емнип.

Но это одна ошибка.

Я посчитал за две — она же дважды повторена.

Где ещё две?

Еще одна, что я имел в виду — это зачем-то (echo "Необходима магия" 1>&2 && exit 1) выполняется в подоболочке, что и само по себе расточительно, но в данном случае еще и exit выйдет именно из нее, а не из всей программы.

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

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

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

Вы как-то забыли ведь упомянуть о том, что переход в каталог + append в файл требует более высоких прав доступа в Unix, нежели просто append в файл?

Извините, не увидел ни малейшего смысла это упоминать. Прямая запись в /var/log/messages — многократно более вопиющая вещь.

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

Речь шла о том, как лучше написать оператор «if», а не о том, как в принципе нужно правильно писать программы.

Речь шла как раз о том, что оператор «if» здесь лучше не писать вообще.

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

Всегда пожалуйста.

К слову, если вы́ знаете разумный пример, при котором echo 1>&2 'something' вернет ошибку, буду рад, если сообщите.

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

А как писать? :) Типа

cd "$targetPath" || \
fatal_ 'Cant cd to %s' "$targetPath"

Ну да, вот только человеку, не программирующему на BASH по ночам, такие конструкции не могут быть свойственны по определению.

Всё приходит с опытом, зачем торопить события и сразу вводить начинающего башефана в полный ступор? :)

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

А как писать? :) Типа

Там вообще cd не нужно делать. Есть имя файла, есть запись в него.

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