Bash-скрипт, содержащий обрабатываемые данные

Bash-скрипт, содержащий обрабатываемые данныеДавайте на примере простого скрипта рассмотрим, как написать скрипт, хранящий данные внутри самого себя. Это будет список задач, хранимый в том же самом скрипте, который добавляет задачи, удаляет их и выводит список задач в его текущем состоянии. Итоговый скрипт будет за вычетом самого списка задач занимать менее 750 байт. Его удобно использовать, например, с Dropbox’ом, Яндекс.Диском или Copy для синхронизации задач между несколькими компьютерами

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

case $1 in
    add|del|show)
        ACTION=$1
        shift
        TASK=$@
        ${ACTION}_task
    ;;
    *)
        show_help
    ;;
esac

У нас есть три команды: add, del, show. Самое первое, что сделаем — запомним действие, которое указано в командной строке, в переменную ACTION. Затем сдвинем позиционные параметры скрипта, чтобы удалить из этого списка само действие. Переменной TASK приравняем содержимое командной строки, которое в итоге получится. После этого запустим функцию с именем ДЕЙСТВИЕ_task, которая выполняет соответствующее действие. Если же в качестве первого параметра указано что-то иное или ничего не указано, будет вызвана функция show_help, отображающая краткую помощь. Вот она:

show_help(){
  cat << EOF

Description: script which keeps tasks list (or any other list) inside itself
Usage: $0 [add|show|del]'

Commands:
  add [task description]
  del [task description part (will delete any tasks that include entered string)]
  show

EOF
exit
}

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

show_task(){
echo "----------TASK LIST--------"
cat << TASKLISTEND
TASKLISTEND
}

Эта функция просто выводит всё, что находится между строкой

cat << TASKLISTEND

и строкой

TASKLISTEND

Именно между этими строками мы и будем хранить список задач. Теперь осталось написать еще две функции: добавление и удаление задачи. Добавлять задачу будем следующим образом:

get_task(){
if [ "$TASK" == "" ]
then
    echo -n "Enter task description: "
    read TASK
fi
}

add_task(){
get_task
sed -i $0 -re "s/(^TASKLISTEND$)/$TASK\n\1/"
$0 show
}

Непосредственно добавлением задачи занимается функция add_task, а функция get_task просто запрашивает с клавиатуры задачу, если она не была указана в командной строке. Добавление осуществляется потоковым редактором sed. Он выполняет следующее действие: находит в файле $0 (сам файл скрипта) строку, в которой содержится слово "TASKLISTEND" и вставляет перед ним еще одну строку, содержащую описание задачи, и перевод строки.

Удаление реализуется похожим образом:

del_task(){
get_task
sed -i $0 -e "/ TASKLISTEND$/,/^TASKLISTEND$/ {/$TASK/d}"
$0 show
}

Как видите, здесь мы тоже получаем описание задачи при помощи функции get_task, а затем выполняем удаление строки из списка, в которой находится часть описания задачи, попадающей в интервал между двумя строками. Строка начала интервала строк содержит пробел и слово TASKLISTEND в конце строки, а строка конца интервала содержит одно единственное слово TASKLISTEND. Между этими двумя строками мы и удаляем найденную строку, если такая есть.

Вот, собственно, и всё. Полный текст скрипта tsklst.sh:

#!/bin/bash

get_task(){
if [ "$TASK" == "" ]
then
    echo -n "Enter task description: "
    read TASK
fi
}

add_task(){
get_task
sed -i $0 -re "s/(^TASKLISTEND$)/$TASK\n\1/"
$0 show
}

del_task(){
get_task
sed -i $0 -e "/ TASKLISTEND$/,/^TASKLISTEND$/ {/$TASK/d}"
$0 show
}

show_task(){
echo "----------TASK LIST--------"
cat << TASKLISTEND
TASKLISTEND
}

show_help(){
  cat << EOF

Description: script which keeps tasks list (or any other list) inside itself
Usage: $0 [add|show|del]'

Commands:
  add [task description]
  del [task description part (will delete any tasks that include entered string)]
  show

EOF
exit
}

case $1 in
    add|del|show)
        ACTION=$1
        shift
        TASK=$@
        ${ACTION}_task
    ;;
    *)
        show_help
    ;;
esac