Домашнее задание на неделю 48

Задания на освоение малых языков IEEE Std 1003.1-2017 (POSIX.1-2017) — awk, bc, find, m4, sh, test. (Помимо текста стандарта, здесь может быть полезно обратиться к главе Minilanguages книги «Искусство программирования Unix.») При оценивании результатов будет приниматься во внимание в первую очередь корректность кода, но также и оптимальность решения. Контрольный срок сдачи — .

  1. Ознакомившись с описанием языка программирования Awk POSIX.1-2017, составьте программы для выполнения следующих преобразований текстового потока.

    1. Первые два поля («столбца») входного потока содержат количество единиц товара и цену за единицу. Вывести все входные записи, добавив к ним строку итога total. При наличии во входных данных строки или строк total — игнорировать их.

      Пример входного потока:

      7 20 dates
      5 30.7 olives
      45 total
      

      Соответствующий вывод:

      7 20 dates
      5 30.7 olives
      293.5 total
      
    2. Поля входного потока могут содержать числа (т. е., удовлетворять регулярному выражению ^[0-9]+(\.[0-9]*)?$ или ^\.[0-9]+$.) Вывести строку, содержащую сумму значений входных записей («строк») для данного поля; или символ - — для полей, в которых отсутствуют числовые данные.

      Пример входного потока:

      10  apples    17 31
      30  oranges    .07
      25  pears      3 9 ***
      

      Соответствующий вывод:

      65 - 20.07 40 -
      
    3. Исключить из входного потока вторую и последующие копии строк, если таковые имеются. Строки, начинающиеся на различное (включая 0) число символов *, но в остальном идентичные, считать копиями.

      Пример входного потока:

      starboard bread
      *** ready Bolivian
      annoying sailboats
      shelter gray
      *annoying sailboats
      * ready Bolivian
      

      Соответствующий вывод:

      starboard bread
      *** ready Bolivian
      shelter gray
      annoying sailboats
      
    4. Простым способом получить список файлов директории d, измененных последними, является следующий конвейер: ls -t -- d | head. К сожалению, этот способ не работает для случая нескольких директорий (ls -t -- d1 d2 d3) Предложите вариант вызова awk, который можно было бы использовать вместо head для обработки вывода команды ls -t для произвольного количества директорий.

    5. Извлечь из файла /proc/mounts имена файлов устройств (первое поле), несущих файловые системы, подключенные в режиме «чтение и запись» (четвертое поле содержит слово rw.) Исключить повторы. Игнорировать записи для файловых систем, не связанных с устройствами (т. е. первое поле для которых не начинается на /dev/.)

      Пример входного потока:

      proc /proc proc rw,nodev,noexec,nosuid,relatime 0 0
      /dev/mapper/vgjay--i-lvhome--z5de3d3 /home ext4 rw,nodev,nosuid 0 0
      /dev/sr0 /media/cdrom iso9660 ro,nodev,nosuid 0 0
      

      Соответствующий вывод:

      /dev/mapper/vgjay--i-lvhome--z5de3d3
      
  2. Ознакомившись с описанием команды bc POSIX.1-2017, составьте программы для выполнения следующих вычислений.

    1. Математических констант e (число Эйлера — основание натуральных логарифмов) и π (отношение периметра окружности к ее диаметру) — с точностью 100 десятичных знаков.

    2. Корня уравнения x = cos x — с точностью не хуже 10−5.

      (Обратите внимание, что отображение y = cos x является сжимающим.)

  3. Ознакомившись с описанием команды find POSIX.1-2017, запишите команды для выполнения (рекурсивного, если не указано иного) поиска и обработки найденных файлов по следующим условиям.

    1. Найти в текущей директории все файлы с именами, заканчивающимися на .jpeg и .jpg без учета регистра, не находящиеся в директориях .old (и поддиректориях таких директорий.)

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

    3. Рекурсивно найти и удалить все пустые поддиректории директории toivu. (Под пустыми в данном случае понимать директории, не содержащие иных файлов, кроме, быть может, других пустых директорий.)

    4. Для каждого обычного файла директории ashi (и ее поддиректорий) проверить, существует ли в директории wyst файл с таким же относительным именем (например, файлу ashi/eicus/grydoj соответствует wyst/eicus/grydoj) и совпадающим с исходным файлом побайтово (в смысле команды cmp) содержимым. Вывести список таких файлов.

    5. Найти в /etc обычные файлы с именами, заканчивающимися на .dpkg-dist. Для каждого из таких файлов выполнить команду вида diff -u -- filename.dpkg-dist filename.

    6. Используя find определить, является ли временна́я отметка последнего изменения (англ. m-time) файла bonio более поздней, чем таковая файла evdop. Обратите внимание, что любой из этих файлов может быть директорией; рекурсию в этом случае следует подавить.

  4. Параметрами макропрограммы на языке m4 являются ширина (WIDTH) и высота (HEIGHT) дисплея в пикселах. Выбрать из списка ниже шрифт семейства Terminus наибольшего размера такой, чтобы на экран помещалось не менее 80 символов в строке по ширине и не менее 30 строк по высоте. Выводом программы должна быть одна строка вида:

    UXTerm.VT100.font: шрифт
    

    Обратите внимание, что в идентификаторе шрифта X ниже поле 7 (12, 14, …, 32) дает высоту шрифта в пикселах; поле 12 (60, 80, …, 160) — ширину в десятых долях пиксела.

    -xos4-terminus-medium-r-normal--12-120-72-72-c-60-iso10646-1
    -xos4-terminus-medium-r-normal--14-140-72-72-c-80-iso10646-1
    -xos4-terminus-medium-r-normal--16-160-72-72-c-80-iso10646-1
    -xos4-terminus-medium-r-normal--18-180-72-72-c-100-iso10646-1
    -xos4-terminus-medium-r-normal--20-200-72-72-c-100-iso10646-1
    -xos4-terminus-medium-r-normal--22-220-72-72-c-110-iso10646-1
    -xos4-terminus-medium-r-normal--24-240-72-72-c-120-iso10646-1
    -xos4-terminus-medium-r-normal--28-280-72-72-c-140-iso10646-1
    -xos4-terminus-medium-r-normal--32-320-72-72-c-160-iso10646-1
    
  5. Ознакомившись с описанием языка shell POSIX.1-2017, разработайте код, выполняющий следующие действия. (При необходимости — обратитесь к разделу XCU стандарта в целом.)

    1. Переменная f содержит имя файла. Поместить в переменные d и b директорию, в которой расположен этот файл, и его имя относительно этой директории, соответственно. Обратите внимание, что: для имен файлов, не содержащих /, директорией следует считать .; все символы /, на которые заканчивается имя файла, следует игнорировать.

    2. Переменная f содержит имя обычного файла. Поместить в переменную z количество MiB-блоков, необходимых для хранения содержимого этого файла. (Так, для файла длиной 1 байт требуется один такой блок — как и для файла длиной 1048576 байт; данные длиной 1048577 байт, однако, потребуют уже двух таких блоков.)

    3. Позиционными аргументами shell-программы являются имена файлов с суффиксами .ppm и .pgm. Для каждого из файлов выполнить команду вида convert filename.ppm filename.jpeg. Если существует и не пуста переменная окружения CONVERT — использовать ее значение в качестве выполняемой команды вместо convert.

    4. Выполнить команду diff -u -- для каждой пары позиционных аргументов, начиная с первого. Например, для списка аргументов imsye fenbi tejru nemix, выполнить следующие команды:

      diff -u -- imsye fenbi
      diff -u -- fenbi tejru
      diff -u -- tejru nemix
      
    5. Составить функцию elt, выводящую на стандартный вывод аргумент с номером, равным значению первого аргумента плюс 2. (Т. е., elt 1 foo bar выводит значение третьего аргумента функции — строку bar.) Если функции передано недостаточное количество аргументов — возвратить ненулевой код завершения.

  6. Программа на shell начинается следующими строками. Объясните их смысл.

    #!/bin/sh
    set -e
    set -C -u