Интерпретатор SHELL ,   некоторые утилиты

    Внутренняя команда -- это команда, которая встроена непосредственно в Bash (Shell). Команды делаются встроенными либо из соображений производительности, встроенные команды исполняются быстрее чем внешние, которые, как правило запускаются в дочернем процессе, либо из-за необходимости прямого доступа к внутренним структурам командного интерпретатора.

    Действие, когда какая либо команда или сама командная оболочка инициирует (порождает) новый под процесс, что бы выполнить какую либо работу, называется ветвлением (forking) процесса. Новый процесс называется "дочерним" (или "потомком"), а породивший его процесс -- "родительским" (или "предком"). В результате и потомок и предок продолжают исполняться одновременно -- параллельно друг другу.

    В общем случае, встроенные команды Bash(Shell), при исполнении внутри сценария, не порождают новый под процесс, в то время как вызов внешних команд, как правило, приводит к созданию нового под процесса.

    Внутренние команды могут иметь внешние аналоги. Например, внутренняя команда Bash -- echo имеет внешний аналог /bin/echo и их поведение практически идентично.

https://www.opennet.ru/bash_scripting_guide  <-bash built-in commands    

                                                 Complete list of shell built-in commands

trap

http://freaksidea.com/shell-obrabotka-sighnalov

https://studfiles.net/trap

https://www.ibm.com/developerworks/using TRAPS

https://bash.cyberciti.biz/guide/Trap_statement

http://ashep.org/2010/obrabotka-signalov     <---------------

http://www.tutorialspoint.com/unix/unix-signals-traps.htm

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

 

$ kill -l                                      # Список сигналов

Формат команда следующий:

trap "имя" сигнал(ы)

trap 'echo "Ctrl-C Ignored" ' INT

Имя представляет собой функцию, содержащую инструкции, которые выполняются при перехвате сигнала. В действительности функцию следует называть так, чтобы ее имя было связано именно с перехваченными сигналами. Имя следует заключать в двойные кавычки (" "). Сигналы являются входящими. Когда сигнал перехватывается, сценарий обычно находится в стадии обработки. Самые распространенные действия следующие:

   1. Очистить временные файлы.

   2. Игнорировать сигналы.

   3. Запросить пользователя, следует ли завершить сценарий.

Наиболее распространенные варианты применения команды trap

 trap " " 2 3 Игнорирование сигналов 2 и 3; пользователь не может завершить сценарий

 trap "команды" 2 3 Если захвачены сигналы 2 и 3, выполняются команды

 trap 2 3 Восстановление сигналов 2 и 3; пользователь может завершить сценарий

***Вместо двойных кавычек можно использовать одинарные; результат будет аналогичен.



Функция my_exit вызывается при получении сигнала 2; при этом отображается значение переменной $LOOP, информирующее пользователя о том, какая итерация цикла выполнялась при нажатии комбинации клавиш [Ctrl-C].  Функции подобного типа применяются на практике для удаления временных файлов. При выполнении сценария получим следующие результаты:

  trap1

1

2

3

4

5

6

7

..........

..........

..........

580

581

582

583

^C    You just hit <CTRL-C>, at number 583

          I will now exit

Перехват сигналов и выполнение действий

    На примере завершения работы некого бесконечного цикла удобно проиллюстрировать выполнение команды trap, итак создадим сценарий, выполняющий подсчет итераций до тех пор, пока пользователь не нажмет комбинацию клавиш [Ctrl+C] (sig-2  SIGINT). После этого сценарий отобразит сообщение, содержащее номер текущей итерации цикла.

В этом случае применяется следующий формат:

trap "какие-либо действия" номер сигнала: (№)

Соответствующий сценарий будет имееть вид:

$ cat > trap1

#!/bin/sh

#trap1

trap "my_exit" 2

LOOP=0

my_exit ()

{

echo "  You just hit <CTRL-C>, at number $LOOP"

echo "     I will now exit "

sleep 4

exit 1

}

while

do

LOOP=`expr $LOOP + 1`

echo $LOOP

done

^C

Рассмотрим сценарий более подробно:

trap "my_exit" 2

В результате выполнения команды trap после получения сигнала 2 (прерывание при помощи клавиатуры CTRL-C) выполняется команда, заключенная в двойные кавычки; в данном случае вызывается функция my_exit:

my_exit ()

{

echo "You just hit <CTRL-C>, at number $LOOP"

echo " I will now exit "

exit 1

}

Захват сигнала и выполнение действий

    Наиболее часто выполняемым действием является удаление временных файлов.

В следующем сценарии с помощью команд df и ps непрерывно добавляется информация во временные файлы HOLD1.$$ и HOLD2.$$. Не забывая, что символы $$ заменяют ID процесса. Когда пользователь нажимает комбинацию клавиш [Ctrl+C], эти файлы удаляются.

$ cat > trap2

#!/bin/sh

# trap2

# перехват только сигнала 2….<CTRL-C>

trap "my_exit" 2

HOLD1=/tmp/HOLD1.$$

HOLD2=/tmp/HOLD2.$$

my_exit ()

{

# my_exit

echo "    <CTRL-C> detected..Now cleaning up..wait"

# удаление временных файлов

rm /tmp/*.$$ 2>/dev/null

exit 1

}

echo "processing…."

# основной цикл

while :

do

df >> $HOLD1

ps xa >>$HOLD2

done

^C

$ chmod 744 trap2

$ trap2

processing….

^C  <CTRL-C> detected..Now cleaning up..wait

    При получении сигнала можно предоставлять пользователю определенный выбор. Однако если получены сигналы 2 или 3, следует убедиться, что они не появились случайно. Необходимо предусмотреть поток ошибок, благодаря чему выявляется ошибочное нажатие клавиш [Ctrl+C].

В следующем примере пользователю предоставляется возможность решить, следует ли выйти из сценария после получения сигнала 2. Отображается запрос о том, действительно ли пользователь желает завершить работу. Для уточнения предпринимаемого действия применяется конструкция case.

    Если пользователь желает выйти из сценария, он выбирает 1, в результате чего после отображения статуса "exit 1" запускается процесс очистки. Если пользователь не желает выходить из сценария, никакие действия не производятся; зададим, что при выполнении конструкции case результаты выбора будут неудачными и произойдет возврат к исходному коду. Конечно, при подтверждении должны захватываться значения всех пустых полей.

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

my_exit () 

{

# my_exit

echo -e "\nReceived interrupt …" 

echo "Do you really wish to exit ???" 

echo " 1: Yes" echo " 2: No"

echo -n " Your choice [1..2] >" 

read ANS 

case $ANS in

1) # удаление временных файлов.. и т. д…

exit 1

;;

# не выполняет ничего

;; 

esac

}

Если при выполнении этого сценария происходит нажатие клавиш [Ctrl+C] в середине поля ввода (сразу после начала ввода имени), то пользователю предоставляется выбор: возвратиться к обычной обработке или выйти из сценария.

Соответствующий сценарий выглядит так:

$ cat > trap3

#!/bin/sh

#trap3

#перехват сигналов 1 2 3 и 15

trap "my_exit" 1 2 3 15

LOOP=0

# временные файлы

HOLD1=/tmp/HOLD1.$$

HOLD2=/tmp/HOLD2.$$

my_exit()

{

# функция my_exit

echo -e "\nRecieved interrupt…"

echo "Do you wish to really exit ???"

echo " Y: Yes"

echo " N: No"

echo -n " Your choice [Y..N] >"

read ANS

case $ANS in

Y|y) exit 1;; # выход из сценария

N|n) ;;         # возврат к обычной обработке

esac

}

# цикл while применяется здесь, например, для просмотра полей

echo -n "Enter your name :"

read NAME

echo -n "Enter your age :"

read AGE

^C

$ chmod 744 trap3

$ trap3

Enter your name :nobody

Enter your age :

$ trap3

Enter your name :^C

Recieved interrupt…

Do you wish to really exit ???

Y: Yes

N: No

Your choice [Y..N] >y

Файл .logout

    Одним из недостатков интерпретатора Bourne shell является отсутствие в нем файла .logout. Этот файл содержит команды, которые требуется выполнить непосредственно перед завершением сеанса работы в системе, т. е. до выполнения команды exit.

    Однако собственный файл .logout интерпретатора Bourne shell можно создать с помощью команды trap. Как это делается? Отредактируйте свой файл .profile (.bashrc) и разместите на последней строке приведенную ниже команду. Затем сохраните этот файл и выйдите из режима редактирования.

 trap "$HOME/.logout" 0

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

$ ~ vim .logout

rm -f $HOME/*.log

    rm -f $HOME/*.tmp

    figlet -f slant "R.I.P $LOGNAME"

    sleep 3

$ ~

Файл .logout вызывается при выходе пользователя из системы. Когда пользователь выходит из среды интерпретатора shell, система посылает сигнал Ø, который и означает выход из текущего интерпретатора shell. Прежде чем управление передается обратно интерпретатору shell, для продолжения процесса выхода из системы, упомянутый выше сигнал перехватывается командой trap. Эта команда находится в соответствующей строке файла .profile (.bashrc).  Затем выполняется файл .logout.

Блокировка терминала

    Ниже приводится сценарий, в котором предлагается другой путь для перехвата сигналов в функционирующем сценарии. Сценарий lockit блокирует терминал пользователя с помощью командной строки. При этом командная строка помещается в непрерывный цикл while. Команда trap захватывает сигналы 2, 3 и 15. Если пользователь пытается прервать выполнение сценария, отображается сообщение о том, что действия пользователя не были успешными.

    При первом обращении к сценарию запрашивается пароль. Для отмены блокировки терминала сведения поступают из устройства /dev/tty, следовательно, отсутствует запрос на разблокировку терминала; нужно просто ввести пароль и нажать клавишу ввода.

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

Если сценарий уничтожен с помощью другого терминала, можно вернуться на ваш терминал и разобраться с проблемами, связанными с настройками терминала: например, выяснить, почему не функционирует клавиша ввода. По командному запросу воспользуйтесь приведенной подсказкой. Это позволит устранить большую часть затруднений, связанных с терминалом.

$ stty sane

Сценарий имеет вид:

$ ~  cat > lockit

#!/bin/sh

#lockit

#перехват сигналов 2 3 и 15

trap "nice_try" 2 3 15

#устройство, на котором выполняется сценарий

TTY=`tty`

nice_try ()

{

# nice_try

echo "Nice try, the terminal stays locked"

}

# сохраните настройки stty, скрытие символов при вводе пароля

SAVEDSTTY=`stty -g`

stty -echo

echo -n "Enter your password to lock $TTY :"

read PASSWORD

clear

while :

do

# чтение только из tty !!

read RESPONSE < $TTY

if [ "$RESPONSE"="$PASSWORD" ]; then

# пароль соответствует…разблокировка

echo "unlocking…"

break

fi

#отображение сообщения, если пользователь введет неверный пароль

#или нажмет клавишу ввода

echo "wrong password and terminal is locked.."

done

# восстановление настроек stty:  stty=$SAVEDSTTY

^C

$ ~ chmod 744 lockit

$ ~ export PATH=$PATH:~

Вывод сценария lockit: 

$ lockit

Enter your password to lock /dev/tty1 :

    Затем экран очищается. При нажатии клавиши ввода или наборе неверного пароля сценарии выводит следующие данные:

wrong password and terminal is locked..

Nice try, the terminal stays locked

wrong password and terminal is locked..

Nice try, the terminal stays locked '

Введите правильный пароль

unlocking… 

$     #Теперь возвращаемся обратно, в командную строку.

Игнорирование сигналов

    Когда пользователь регистрируется в системе, просматривается файл /etc/profile; нежелательно, чтобы пользователь прерывал этот процесс. Обычно задается перехват, или игнорирование, сигналов 1, 2, 3 и 15, но потом при просмотре сообщения motd (ежедневного сообщения) их подключают вновь (восстанавливают). Затем для игнорирования сигналов 1, 2, 3 и 15 снова устанавливается перехват.

Аналогичный подход можно, реализовать при работе со сценариями. Можно ввести понятие критического момента, который наступает при открытии большого количества файлов. Начиная с этого момента, нельзя прерывать выполнение сценария, поскольку это может повредить файлы. Для решения этой проблемы следует установить, команду trap, что позволит игнорировать некоторые сигналы. Когда завершится критический момент в функционировании сценария, примените команду trap, чтобы снова можно было захватывать сигналы.

    Для игнорирования входящих сигналов (кроме сигнала 9) применяется следующая команда:  trap "" номер_сигнала:{s}  Обратите внимание, что двойные кавычки ничего не содержат. Чтобы восстановить перехват и заново захватывать сигналы, выполните команду:  trap "любые действия" номер_сигнала:{s}

Суммируем сведения о процессах игнорирования и выявления сигналов.

trap "" 1 2 3 15                 # игнорирование сигналов 

code that does really critical stuff

trap "my_exit" 1 2 3 15    # выполните снова захват сигналов с помощью функции my_exit

  Обратите внимание на сценарий, выполняющий критическую обработку. Цикл while аккуратно передвигает имеющийся критический момент. Для игнорирования сигналов 2, 3 и 15 применяется команда trap. После завершения цикла while, завершается еще один цикл while, но перехват уже восстановлен и прерывания разрешены.

    Оба цикла while выполняются до завершения шести итераций, затем в цикле активизируется команда sleep. Благодаря этому имеется достаточно времени для того, чтобы прервать выполнение сценария. Рассмотрим следующий сценарий:

$ ~ cat > trap_ignore

#!/bin/sh

#trap_ignore

#игнорирование сигналов

trap "" 1 2 3 15

LOOP=0

my_exit ()

# my_exit

{

echo "Received interrupt on count $LOOP"

echo "Now exiting…" exit 1

}

# критическая обработка, нельзя прерывать….

LOOP=0

while :

do

LOOP=`expr $LOOP + 1`

echo "critical processing..$LOOP..you cannot interrupt me"

sleep 1

if [ "$LOOP" -eq 6 ]; then

break

fi

done

LOOP=0

#критическая обработка завершена, перехват задан снова, но разрешены прерывания

trap "my_exit" 1 2 3 15

while :

do

LOOP=`expr $LOOP + 1`

echo "Non?critical processing..$LOOP..interrupt me now if you want"

sleep 1

if [ "$LOOP" -eq 6 ]; then

break

fi

done

^C

$ ~ chmod 744 trap_ignore

$ ~ trap_ignore

critical processing..1..you cannot interrupt me

critical processing..2..you cannot interrupt me

critical processing..3..you cannot interrupt me

critical processing..4..you cannot interrupt me

critical processing..5..you cannot interrupt me

critical processing..6..you cannot interrupt me

Non?critical processing..1..interrupt me now if you want

Non?critical processing..2..interrupt me now if you want

Non?critical processing..3..interrupt me now if you want

^CReceived interrupt on count 3

Now exiting… exit 1

$ ~

    Если в процессе работы этого сценария попытаться нажать клавиши [Ctrl+C] во время выполнения первого цикла "критической обработки", ничего не произойдет. Это связано с тем, что была введена команда trap для игнорирования сигналов.

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

    Благодаря применению команды trap можно обрести большую степень контроля над "поведением" сценария при получении сигнала. Перехват и последующая обработка сигналов обеспечивают устойчивую работу сценариев.

eval

    Команда eval (от evaluate - означивать) служит для оценки командной строки с целью завершения каких-либо подстановок интерпретатора shell с последующим их вызовом. Команда eval используется для "расширений" значений переменных ("расширение" заключается  и в том, что если в результате одного прохода расширения не происходит (то есть выполнения всей структуры переменной), выполняется второй проход). Переменные, для оценки которых требуется два прохода, иногда называют сложными переменными. Сложные переменные программист создаёт для хранения данных, имеющих внутреннюю структуру, это удобно поскольку есть возможность обратиться напрямую к любому элементу. Самыми характерными примерами сложных типов являются массив (все элементы однотипные) и запись (элементы могут иметь разный тип). 

    Следует подчеркнуть относительность такого деления: для разных программ одна и та же переменная может иметь разную структуру. Например, компилятор различает в переменной вещественного типа 4 поля: знаки мантиссы и порядка, плюс их значения, но для программиста, компилирующего свою программу, вещественная переменная — единая ячейка памяти, хранящая вещественное число.

    В целом: команда eval передает заданные в ней параметры оболочке в качестве ввода. Таким образом, строка "параметр" обрабатывается дважды: при обработке команды eval и при интерпретации команды оболочкой (в этом похоже и скрыта вся магия).

    Наилучшим методом для понимания работы команды eval является изучение оценки командной строки, выполняемой этой командой, и самым лучшим, по скольку "нормальным" языком объяснить смысл eval все равно не выйдет, это изучение примеров, eval так же может применяться для отображения значений простых переменных; эти переменные не должны быть сложными. Следующий пример наглядно демонстрирует, что смысл eval возможно понять только после стакана:

Выполнение команд, находящихся в строке

    Следующий пример более доходчиво иллюстрирует работу команды eval, для чего создадим небольшой файл, testf, содержащий некоторый текст. Затем переменной myfile будет присвоена команда cat testf с последующим отображением значения переменной (как пример "сложной" переменнной). Благодаря этому можно проверить возможность отображения на экране содержимого файла testf.

$ cat > testf

May Day, May Day Going Down

^C

$

Присвоим переменной myfile строку "cat testf:

$ MYFILE="cat testf"

Если требуется вывести содержимое файла testf на экран, нужно выполнить команду cat testf.

$ echo $MYFILE

cat testf

$

Теперь применим команду eval для оценки значения переменной; вспоминая, что eval выполняет два прохода при оценке переменной myfile.

$ eval $MYFILE

May Day, May Day Going Down

$

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

Другой не менее показательный пример:

    Переменной cat_passwd будет присвоена строка "cat /etc/passwd | more". Команда eval выполняет оценку содержимого данной строки.

$ CAT_PASSWD="cat /etc/passwd | more"

$ echo $CAT_PASSWD

cat /etc/passwd | more

$

$ eval $CAT_PASSWD

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/usr/bin/nologin

daemon:x:2:2:daemon:/:/usr/bin/nologin

mail:x:8:12:mail:/var/spool/mail:/usr/bin/nologin

ftp:x:14:11:ftp:/srv/ftp:/usr/bin/nologin

http:x:33:33:http:/srv/http:/usr/bin/nologin

uuidd:x:68:68:uuidd:/:/usr/bin/nologin

dbus:x:81:81:dbus:/:/usr/bin/nologin

nobody:x:99:99:nobody:/:/usr/bin/nologin

.....................................

$

Команда eval также хорошо подходит для отображения значения последнего параметра, передаваемого сценарию.

$ cat > evalit

#!/bin/sh

#evalit

echo " Total number of arguments passed is $#"

echo " The process ID is $$"

echo " Last argument is " $(eval echo \$$#)

^C

$

При выполнении этого сценария получим следующий результат :

$ evalit a_alpha b_bravo c_charlie 

Total number of arguments passed is 3

 The process ID is 6857

 Last argument is  c_charlie

$

 В этом сценарии команда eval сначала оценивает значение переменной $$ в сравнении с ID процесса, а при выполнении второго прохода производится оценка последнего параметра, передаваемого переменной.  

 Присвоение значения имени переменной    

Можно также поставить в соответствие полю данных имя переменной. Рассмотрим, что это означает на практике, предположим, что в нашем распоряжении имеется следующий файл:

$ ~ cat > data

PC  486

MONITOR  svga

NETWORK  yes

^C

$ ~

    Нам необходимо, чтобы первому столбцу текста соответствовали имена переменных, а второму столбцу текста — значения соответствующих переменных. При этом должно отображаться следующее:

$ ~ echo $PC

$ ~ 486

И вот как  можно достичь желаемого результата.

$ ~ cat > eval_it

#!/bin/sh

#eval_it

while read NAME TYPE

do

eval `echo "${NAME}=${TYPE}"`

done < data

echo "You have a $PC pc, with a $MONITOR monitor"

echo "and have you network? $NETWORK"

^C

$ ~

    Рассмотрим, как функционирует сценарий. Сначала берутся значения рс и 486, которые присваиваются переменным name и type соответственно. При первом проходе команда eval отображает на экране два значения переменных, PC и 486; во время выполнения второго прохода вместо переменной name подставляется значение рс, а вместо переменной type — значение 486. При выполнении сценария получаются следующие результаты:

$ eval_it

You have a 486 pc, with a svga monitor

and have you network? yes

$

В итоге выясняется, что команда eval вовсе не бессмысленна, а вернее наоборот  весьма полезна при использовании в сцкнариях (http://www.softpanorama.org/Utilities/eval.shtml). 

logger

    logger — unix-утилита,  CLI - интерфейс для модуля системного журнала syslog.

Простая, но весьма полезная команда . Эта команда пишет данную ей в аргументе текстовую строку в системный лог (/var/log/messages). С ее помощью можно заносить в лог определенные записи, например отмечать там свои действия.

$ logger test  14:52

$ sudo grep test /var/log/messages

Jun 18 14:52:30 : test 14:52

https://habrahabr.ru/post/281601/

http://www.commandlinefu.com/commands/logger/

basename & dirname

Формат: $  basename  [путь]

    Команда basename выделяет путь из имеющегося имени пути и просто возвращает имя файла. Эта команда обычно применяется в конструкциях usage в сценариях. В этом случае подстановка используется при отображении на экране имен файлов.

$ basename /home/myscript

my script

............

echo " Usage: `basename $0`  give me a file "

exit 1

.............

Если приведенный выше код именуется myscript, вывод может быть следующим:

Usage: "scriptname" give me a file

Здесь $0 является специальной переменной, которая печатает имя сценария.

$ ~ basename --help

Использование: basename ИМЯ [СУФФИКС]

       или:    basename КЛЮЧ… ИМЯ…

Выводит ИМЯ без предшествующих названий каталогов.

Если указано, удаляет также завершающий СУФФИКС.

Аргументы, обязательные для длинных ключей, обязательны и для коротких.

  -a, --multiple       принять несколько аргументов и считать каждый ИМЕНЕМ

  -s, --suffix=СУФФИКС удалить завершающий СУФФИКС; подразумевает -a

  -z, --zero           заканчивать каждую строку результата NUL,

                       а не символом новой строки

Примеры:

  basename /usr/bin/sort          -> «sort»

  basename include/stdio.h .h     -> «stdio»

  basename -s .h include/stdio.h  -> «stdio»

  basename -a any/str1 any/str2   -> за «str1» выведется «str2»

$ ~

dirname

Формат: $ dirname [имя  пути]

В противоположность команде basename, команда dirname выводит на экран

только имя пути

$ ~ dirname --help

Использование: dirname [КЛЮЧ] ИМЯ…

Выводит каждое ИМЯ, удаляя компонент у последней косой черты; если ИМЯ не

содержит косой черты, выводит «.» (то есть текущий каталог).

  -z, --zero       завершать каждую выводимую строку NUL,

                         а не символом новой строки

Примеры:

  dirname /usr/bin/          -> «/usr»

  dirname dir1/str dir2/str  -> за «dir1» выводится «dir2»

  dirname stdio.h            -> «.»

$ ~

script

    Не бесполезная, а местами весьма полезная команда для логирования происходящего в терминале. Чтобы начать запись нужно выполнить команду script. Если вызвать команду script без параметров, то записьбудет произведена в файл с именем typescript.

$ ~ script

Скрипт запущен, файл — typescript

$ ~  #и будет писаться до Ctrl+D (exit)

$ ~ exit

Скрипт выполнен, файл - typescript

$ ~

    В качестве параметра команде script можно указать имя файла, в который вы хотите записывать всю активность в терминале. После ввода команды будет создан файл, но данные в него будут записаны только после того, как вы введете команду exit или нажмете сочетание клавиш Ctrl+D. Если вы хотите, чтобы запись велась уже в существующий файл, тогда нужно добавить опцию -a. В этом случае файл не будет очищен, а новые данные будут добавлены к текущему содержимому.  Опция -c или —command, позволяет указать команду, которую нужно выполнить, а вывод этой команды записать файл.

$ ~ script -c ls -a

Скрипт запущен, файл — typescript

 AUR          arraytest.awk      fieldcheck.awk   loganalyzer-3.6.3    textfind

 DEB          belts.awk          file_func        mix.sed              trap_ignore

 Desktop      butt.jpg           for.while        myfile               ttest

 Downloads    change.sed         func_02_02       pas1                 typescript

 Mail         data               func_o1          passwd.awk           v_args

 News         drive.google.com   insert.sed       purple-hangouts-hg   whilecount

 RPM          eval_it            irssi            stock.txt            whileread

 aaaaa        evalit             kdenlive         student_tot.awk      wxHexEditor

 age.awk      exec_s.txt         lmms             study                wxHexEditor-v0.23-src.tar.bz2

 append.sed   f_desc             lockit           testf               

Скрипт выполнен, файл - typescript

$ ~ cat typescript

Скрипт запущен Ср 11 окт 2017 22:39:58

 AUR                evalit              passwd.awk

 DEB                exec_s.txt          purple-hangouts-hg

 Desktop            f_desc              stock.txt

 Downloads          fieldcheck.awk      student_tot.awk

 Mail               file_func           study

 News               for.while           testf

 RPM                func_02_02          textfind

 aaaaa              func_o1             trap_ignore

 age.awk            insert.sed          ttest

 append.sed         irssi               typescript

 arraytest.awk      kdenlive            v_args

 belts.awk          lmms                whilecount

 butt.jpg           lockit              whileread

 change.sed         loganalyzer-3.6.3   wxHexEditor

 data               mix.sed             wxHexEditor-v0.23-src.tar.bz2

 drive.google.com   myfile             

 eval_it            pas1

Скрипт выполнен Ср 11 окт 2017 22:39:58

$

$ man script

SCRIPT(1)                                    User Commands                                    SCRIPT(1)

NAME

       script - make typescript of terminal session

SYNOPSIS

       script [options] [file]

DESCRIPTION

       script  makes  a typescript of everything displayed on your terminal.  It is useful for students

       who need a hardcopy record of an interactive session as proof of an  assignment,  as  the  type‐

       script file can be printed out later with lpr(1).

       If the argument file is given, script saves the dialogue in this file.  If no filename is given,

       the dialogue is saved in the file typescript.

OPTIONS

       -a, --append

              Append the output to file or to typescript, retaining the prior contents.

       -c, --command command

              Run the command rather than an interactive shell.  This makes it easy  for  a  script  to

              capture the output of a program that behaves differently when its stdout is not a tty.

       -e, --return

              Return  the  exit code of the child process.  Uses the same format as bash termination on

              signal termination exit code is 128+n.

       -f, --flush

              Flush output after each write.  This is nice for telecooperation: one person does `mkfifo

              foo;  script  -f  foo', and another can supervise real-time what is being done using `cat

              foo'.

       --force

              Allow the default output destination, i.e. the typescript file, to be a hard or  symbolic

              link.  The command will follow a symbolic link.

       -q, --quiet

              Be  quiet  (do  not  write start and done messages to either standard output or the type‐

              script file).

...................................................

Утилита . (точка) или source: Запуск исполняемого файла в текущей оболочке

    Чтобы после редактирования такого файла запуска, как .bashrc, изменения вступили в силу, не нужно выходить из системы и снова в нее входить. Вместо этого нужно запустить файл запуска с помощью встроенной утилиты . (точка) или source (при использовании bash это одна и та же команда, но при использовании оболочки tcsh доступна только команда source). Как и все остальные команды, команда . (точка) должна сопровождаться в командной строке пробелом. Использование команды . (точка) или source аналогично запуску сценария оболочки, за исключением того, что эти команды запускают оболочку в качестве составной части текущего процесса. Следовательно, когда вы используете . (точка) или source для запуска сценария, те изменения, которые внесены в переменную из этого сценария, воздействуют на оболочку, из которой запущен сценарий. Если файл запуска был запущен как обычный сценарий оболочки, без использования встроенной утилиты . (точка) или source, переменные, которые были созданы в файле запуска, будут действительны только для той подчиненной оболочки, в которой выполнялся сценарий, а не для той оболочки, из которой он был запущен. Команду . (точка) или source можно использовать для запуска любого сценария оболочки, а не только файла запуска, но с возможными нежелательными побочными эффектами (такими как изменения в значениях переменных оболочки).

Создание уникальных временных файлов

    Переменная $$ содержит ID или номер процесса, выполняющегося в текущий момент. Эти сведения применяются при создании временных файлов в текущем сценарии, поскольку ID процесса уникален в рамках сценария. Достаточно лишь создать файл и присоединить к нему символ $$, После завершения можно удалить все файлы, имеющиесимвол $$ в качестве расширения. Интерпретатор shell оценивает переменную $$ как текущий ID процесса и удаляет эти файлы, но оставляет файлы, к которым присоединен ID процесса. В командной строке введите следующую команду:

$ echo $$

456

Ниже приводится сценарий, который создает два временных файла, обрабатывает и затем удаляет их.

$ ~ vim tempfiles

#!/bin/sh

#tempfiles

#именование временных файлов

HOLD1=/tmp/hold1.$$

HOLD2=/tmp/hold2.$$

#выполнений некой  обработки с помощью этих файлов

df >$HOLD1

cat $HOLD1 >HOLD2

#удаление временных файлов

rm /tmp/*.$$

 $ ~ cat HOLD2

Файловая система 1K-блоков Использовано Доступно Использовано% Cмонтировано в

dev                     504492             0                            504492            0% /dev

run                      508932            732                         508200            1% /run

/dev/sda1            20511356        11705556               7740840           61% /

tmpfs                   508932            0                            508932             0% /dev/shm

tmpfs                   508932            0                            508932             0% /sys/fs/cgroup

tmpfs                   508932            8                            508924             1% /tmp

/dev/sda2            38057472        30904496              5196728           86% /home

/dev/sda3            19091584        13087868              5010796           73% /mnt/Debian

tmpfs                   101784            0                            101784             0% /run/user/0

tmpfs                   101784            20                          101764             1% /run/user/1000

$ ~

При выполнении этого сценария создаются следующие два файла:

hold1.408 

hold2.408

Когда указывается команда rm /tmp/*.$$, интерпретатор shell в действительности выполняет команду rm /tmp/*.408. Важно помнить, что ID процесса является уникальным только в конкретный момент времени. Например, если приведенный выше сценарий выполнить снова, получим новый ID процесса, поскольку речь идет о другом процессе.

Благодаря использованию даты можно отслеживать файлы, созданные для специальных целей. Помимо этого, значительно облегчается очистка файлов на базе определенных дат, поскольку с первого взгляда видно, какие файлы создавались раньше, а какие позже. Временные файлы создаются легко и быстро; кроме того, они являются уникальными для данного процесса. После того как сценарий завершает обработку, их несложно удалить без искажения остальной информации.При выполнении этого сценария создаются следующие два файла:

Сценарий удаления пустых строк

    Сценарий del.lines может обрабатывать один или несколько файлов. До того, как команда sed приступит к удалению всех пустых строк, проверяется наличие каждого файла. Поток вывода команды sed с помощью символов $$ направляется во временный файл. Затем файл перемещается обратно, заменяя исходный файл. Чтобы просмотреть все имена файлов, применяется команда shift. Цикл while выполняется до тех пор, пока имеются обрабатываемые файлы. Введите команду del.lines -help, в результате чего отобразится немного разреженная справочная строка, при желании лучше  создать более информативную справку.

$ ~ vim del.lines

#!/bin/sh

#del.lines

#сценарий получает имена файлов и удаляет из них все пустые строки

TEMP_F=/tmp/del.lines.$$

usage ()

{

# usage

echo "Usage :`basename $0` file [file..]"

echo "try `basename $0` -help for more info"

exit 1

}

if [ $# -eq 0 ]; then

    usage

fi

FILES=$1

while [ $# -gt 0 ]

do

    echo "..$1"

    case $1 in

    -help) cat <<- MAYDAY

    Use this script to delete all blank lines from a text file

    MAYDAY

    exit 0

    ;;

    *)FILE_NAME=$1

 if [ -f $1 ]; then

  sed '/^$/d' $FILE_NAME >$TEMP_F

  mv $TEMP_F $FILE_NAME

 else

  echo "`basename $0` cannot find this file : $1"

 fi

 shift

 ;;

 esac

done

$ ~ chmod +x del.lines

**** Опция "-"  в встроенном документе <<-

подавляет предшествующие символы табуляции в теле документа, но *не* пробелы.

http://www.bash-scripting.ru/abs/chunks/ch18.html

$ ~ cat > file_21

aaaaa

sssss

ddddd

fffff

ggggg

hhhh

jjjjj

kkkkk

llll

zzzz

xxxxxxxxxxx END

^C

$ ~ del.lines file_21

..file_21

$ ~ cat file_21

aaaaa

sssss

ddddd

fffff

ggggg

hhhh

jjjjj

kkkkk

llll

zzzz

xxxxxxxxxxx END

$ ~ del.lines -help

..-help

Use this script to delete all blank lines from a text file

$ ~