---
# System prepended metadata

title: Лабораторная работа №5 "Bash Certification"

---

# Лабораторная работа №5 "Bash Certification"

---

## **Цели работы:**
- Самостоятельно изучить основы программирования на bash.
- Приобретение навыка обработки документов MS Office bash-скриптом.

---

## Ход работы

### **Задание:** Для выпускников школы срочно нужно заполнить именные грамоты на каждого ребёнка. Разумеется, с помощью bash.

#### Имеется шаблон грамоты (грамота.docx) и список учеников (ФИО.txt)

#### **Результат:** bash-скрипт, который создаёт грамоту в формате docx для каждого ученика.

Итак, для начала стоит посмотреть сами файлы.

1) ФИО.txt

В файле построчно записано по 3 слова - ФИО.

![](https://i.imgur.com/Kv0q24c.png)

2) грамота.docx

В файле представлен макет грамоты, в котором надо заменить "ФИО" на значение из первого файла.

![](https://i.imgur.com/SDsmxOZ.png)


По началу, была идея заменить строку "ФИО" используя команду "sed", не углубляясь в сам файл. Команда выглядел примерно так:

```bash
for FIO in $(cat ФИО.txt); do sed -i "s/ФИО/$FIO/g" грамота.docx > $FIO.gramota.docx; done
```

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

Потом вспомнил, что в отличии о формата doc, docx представляет собой архив. Где необходимый текст содержится в файле /word/document.xml

![](https://i.imgur.com/UcBCB8l.png)

![](https://i.imgur.com/N7SD5xT.png)

![](https://i.imgur.com/IkkBG4o.png)

Уже отталкиваясь от этого факта буду работать дальше.

Был придуман следующий алгоритм:


1) Разархивировать макет грамоты и использовать его для дальнейшего создания новых архивов.
2) Проходясь в цикле по каждой строке файла с ФИО, заменять значение "ФИО" в файле **/word/document.xml**.
3) Полученный "документ", заархивировать обратно в docx файл.

По ходу реализации данной идеи возникло достаточно много ошибок и прочех проблем. Окончательный вариант bash-команды выглядит следующим образом:

```bash
unzip грамота.docx -d gramota; IFS=$'\n'; for fio in $(cat ФИО.txt); do cp -R gramota $fio.gramota; sed -i "s/ФИО/$fio/g" $fio.gramota/word/document.xml; cd $fio.gramota/; zip -r $fio.gramota.docx *; cd ../; cp $fio.gramota/$fio.gramota.docx $fio.gramota.docx; rm -rf $fio.gramota/; done; rm -rf gramota
```

Очевидно, это не лучшая реализация, но главное, что она работает. 

Все грамоты были создано успешно:

![](https://i.imgur.com/9AQquAK.png)

![](https://i.imgur.com/zaostp1.png)

![](https://i.imgur.com/SnFusXg.png)


Теперь рассмотрим саму команду подробно:

1) Разархивация макета.

```bash
unzip грамота.docx -d gramota;
``` 

2) Специальная переменная оболочки "IFS" определяет, как Bash распознает границы слов при разделении последовательности строк символов. По умолчанию IFS представляет собой трехсимвольную строку, состоящую из пробела, табуляции и новой строки. Это значит, что при чтении файла с ФИО, цикл будет проходить не просто по всей строке сразу, а по Имени, Фамилии и Отчеству отдельно - чего нам не нужно. Чтобы исправить это, меняю значение переменной на "новою строку" 

```bash
IFS=$'\n';
``` 

3) Цикл по каждой строке файла ФИО (т.е. по каждой строке ФИО)

```bash
for fio in $(cat ФИО.txt);
``` 

4) Копирую папку с макетом, для дальнейшего его изменения:

```bash
cp -R gramota $fio.gramota; 
``` 

5) Суть всей команды именно эта часть - замена строки "ФИО" на строку из файла ФИО.txt. Параметр **"-i"** - указывает о сохранении изменений в файл. За замену строки отвечает структура: **"s/[Строка которую будем заменять]/[Строка на которую будет замена]"** 

```bash
sed -i "s/ФИО/$fio/g" $fio.gramota/word/document.xml;
``` 

6) Теперь архивирую макет обратно в docx файл. Не уверен в причине, но если запускал команду **zip** вне самой папки с файлами, то структура docx файла была нарушена: все файлы находились внутри ещё одной папки, чего быть не дложно. Поэтому пришлось входить в папку и выходить из неё.

:::danger
![](https://i.imgur.com/79JZGfF.png)
:::

:::success
![](https://i.imgur.com/QVK7VmA.png)
:::

```bash
cd $fio.gramota/; zip -r $fio.gramota.docx *; cd ../;
``` 


7) Достаю документ из папки и удаляю всё то, что осталось. (Команда **"done"** - конец цикла). И сразу удаляю архивированый в начале макет грамоты.


```bash
cp $fio.gramota/$fio.gramota.docx $fio.gramota.docx; rm -rf $fio.gramota/; done; rm -rf gramota

``` 

---


### Заключение

Вероятно, это не самая удачная реализация команды, но она работает!) За время выполнения лабораторной работы столкнулся с множеством мелких проблем (большая из них связана с **"zip"**), но именно этот факт позволил лучше ознакомиться с bash.
