Официальная возможность получить лицензионный софт бесплатно.
Giveaway of the Day
Это не реклама!

Щелкните для получения прогноза по Биробиджану


пятница, 18 сентября 2015 г.

bash: нумерация строк в файле

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

Структура файла данных /var/samba/secret/work (файл был несколько причёсан из исходного сырья):

NNN Текст[;]

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

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

#!/bin/bash
while read
    do
    a=$[a+1]
    deptSA=`echo "$REPLY"|cut -d \  -f 2-|sed "s/\;//"`
    depNSA=${REPLY:0:3}
    printf "%02d:%03d:$deptSA\n" $a $[10#$depNSA]
    if [ -d /var/samba/secret/$depNSA ]
    then
        ln -s /var/samba/secret/$depNSA /var/samba/secret/"$deptSA"
    fi
done</var/samba/secret/work

Файл будем читать построчно в цикле while командой read. Мне лень изощряться, поэтому читаем из stdin, куда файл вливается через переназначение. Вдвойне лень изощряться, поэтому не присваиваю никакую переменную, а использую дефолтную $REPLY.



По-хорошему, переменную-счётчик $a надо бы обнулить перед началом цикла, но задача не критичная и можно положиться на bash, который передает чистое окружение вызываемому процессу.
Для новичков сразу обращу внимание вот на что:
1. в левой части оператора присваивания переменная используется без знака доллара
2. если переменная фигурирует в вычисляемом выражении внутри $(...) или $[...], доллар тоже не нужен. (а вообще, кому он нужен кроме ФРС США?)

Итак, для каждой прочитанной строки выполняются следующие действия:

Выделяем два компонента: в переменную $deptSA попадает текстовое описание каталога, а в переменную $depNSA - номер.
Способов выделить эти компоненты много, я воспользовался первыми, которые пришли в голову. Номер - три цифры, прижатые к началу строки - выделяется очень просто - берем 3 символа, начиная с нулевого. Для текстового компонента (с 5 символа до конца строки) я решил извратиться и воспользоваться командой cut.
Ключ -d задает разделитель полей, именно поэтому после "\" стоят два пробела - первый из них выступает в роли "параметра" для "\". Для наглядности можно было написать "\ ", но два пробела выглядят загадочнее.
Комбинация -f 2- выводит "начиная со второго поля и до конца строки". По сути, раз поля отделяются пробелом, то будет выведено всё, что есть в строке сразу после номера и стоящего за ним пробела-разделителя.
Поскольку в конце текстового описания может быть, а может и не быть точка с запятой, то отрезаем ее с помощью sed.

Команда printf - вывод строки с форматированием - знакома многим, имеющим дело с C-подобными языками. Она берет первым параметром строку форматирования и выводит, согласно оной, последующие параметры. Как раз при выводе номерного имени каталога вылезла бяка, о которой я упоминал в начале статьи: из-за ведущих нулей printf воспринимает ее как восьмеричное число и выпадает в осадок, хорошо хоть не в kernel panic, когда в "восьмеричном" числе обнаруживает цифры 8 и 9. Поэтому пришлось переменную $depNSA принудительно объявлять десятичной.
Использованная мной строка форматирования выводит первый параметр ($a - номер обрабатываемой строки) как десятичное число с двумя знаками, при необходимости - с ведущим нулём, через двоеточие второй параметр - номер каталога - как десятичное с тремя знаками и ведущими нулями, ну и интерпретатор подставляет туда же через еще одно двоеточие значение текстового описания, переменную $deptSA: она не содержит символов процента, поэтому просто выводится командой printf как есть.
Впрочем, этот этап интересен только как пример работы с форматированным выводом, и в данном скрипте используется только для красоты.

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

Наконец, создается собственно символическая ссылка с именем из переменной $deptSA на каталог с именем из переменной $depNSA.

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

Комментариев нет:

Отправить комментарий

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