Unix-way в действии (практические примеры с пояснениями)

Обсуждение развития Open-source.

Модератор: Модераторы разделов

Ответить
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Unix-way в действии

Сообщение t.t »

Предлагаю здесь собирать простые полезные решения в стиле unix-way с краткими пояснениями в стиле "задача -- решение".

В качестве первого примера -- распечатка документов.

На самом деле здесь будет две задачи. Первая задача была достаточно проста: двусторонняя печать на одностороннем принтере. Как оказалось, многие графические программы даже здесь оказались не на высоте: из обязательных требований, список которых ниже, не удовлетворяли в лучшем случае одному (в худшем -- всем). Итак, требуются такие возможности:
1. распечатывать по отдельности чётные и нечётные страницы;
2. печатать чётные страницы в обратном порядке (чтобы не приходилось вручную "перелистывать" всю пачку);
3. задавать разные поля для чётных и нечётных страниц (для последующей сшивки).

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

Для начала был написан такой скрипт:

Shell

t:~/bin$ cat pr #!/bin/bash s=0 [ "$1" == "-s" ] && { s=$2 shift 2 } case "$1" in -o|-1|o|1) p="-o"; l="0(${s}mm,0)" ;; -e|-2|e|2) p="-er"; l="0(-${s}mm,0)" ;; *) exit 1;; esac [ -f "$2" ] || exit 1 psselect $p "$2" | pstops -p a4 $l | lpr


Как видите, всё просто: опцией -s задаётся сдвиг в миллиметрах; обязательный параметр только один и отвечает за то, какие страницы печатать. Т.е. механизм стал такой:
1. "распечатать" в файл нужный документ;
2. выполнить команду (к примеру) pr -s 10 1 имя-файла;
3. дождаться окончания печати и перевернуть стопку бумаги в принтере;
4. выполнить команду (к примеру) pr -s 10 2 имя-файла.

Конечно, тут же захотелось этот процесс автоматизировать. Но тут возникла "параллельная" мысль: хотелось бы распечатывать и читать не стопки листов А4, а книжки. Тут на помощь могут прийти всё те же psutils; в man pstops есть даже соответствующий пример, причём именно для А4. В итоге были написаны ещё три простых скрипта: для преобразования файла со страницами А4 в книгу; для автоматизации процесса печати; и для предварительного просмотра этой книги.

Shell

t:~/bin$ cat kniga #!/bin/bash [ -f "$1" ] || exit 1 cat "$1" | psbook -s16 | pstops -pa4 "2:0L@.7(21cm,0)+1L@.7(21cm,14.85cm)"

Команда psbook переставляет страницы в "книжном" порядке; опция s задаёт размер тетрадки -- в страницах, потому число должно быть кратно 4. Пример команды pstops, как я уже говорил, был взят из мана.

Предпросмотр оказался совсем простым, т.к., оказывается, kde-шная "смотрелка" PostScript умеет принимать данные со stdin:

Shell

t:~/bin$ cat bookview #!/bin/sh kniga "$1" | kghostview -


Скрипт печати тоже не так уж сложен.

Shell

t:~/bin$ cat bookprint #!/bin/bash kniga "$1" >${1%.ps}_kniga.ps pr 1 "${1%.ps}_kniga.ps" || exit 1 zenity --question --title=Печать --text='Печатать вторую сторону?' && pr 2 "${1%.ps}_kniga.ps"


В итоге процесс печати книжки стал, на мой взгляд, "проще некуда":
1. "распечатать" в файл;
2. если нужен предпросмотр, нажать одну из кнопочек на панели;
3. для печати нажать вторую кнопочку;
4. дождаться окончания печати первой стороны, перевернуть стопку и подтвердить продолжение печати в появившемся диалоге.

Единственное лишнее движение диктуется здесь как раз недостаточной гибкостью большинства графических программ, которые умеют сохранять "распечатку" в файл, но не умеют передавать её на stdout.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: Unix-way в действии

Сообщение t.t »

Позволю себе процитировать здесь небольшое пояснение из той дискуссии, в которой родилась идея создания этой темы:
t.t писал(а):
12.11.2009 11:49
Касательно программирования. У этого термина есть достаточно закостенелый смысл, в который работа в командной строке и написание шелл-скриптов не вписываются. Ну никак. Психология процесса совершенно другая. Поэтому я не люблю смешивать это с программированием. Но чисто формально -- да, это своего рода программирование. Я лишь хотел не сосредотачиваться на формальной стороне вопроса, а акцентировать сторону психологическую.

Надеюсь, та разница, о которой я говорю -- между работой в командной строке и программированием -- постепенно будет вырисовываться в новой теме. Пока же пара ссылок в качестве вводной:
http://www.rdb.com/lib/4gl.pdf
http://forum.posix.ru/viewtopic.php?id=932
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
oper777
Сообщения: 411
ОС: gentoo
Контактная информация:

Re: Unix-way в действии

Сообщение oper777 »

t.t писал(а):
12.11.2009 11:00
Предлагаю здесь собирать простые полезные решения в стиле unix-way с краткими пояснениями в стиле "задача -- решение".


Раз в неделю, в пятницу, мне приходится выкачивать с одного FTP некий zip-файл, распаковывать и складывать его содержимое на Windows-smb-сервер в локальной сети. Имя файла каждую неделю - новое. Все, что я знаю, это то, что его выкладывают либо в среду, либо в четверг, либо в пятницу.

Сделал так (samba-сеть монтируется с помощью fusesmb в каталог /net/domain при включении машины):

Код: Выделить всё

#!/bin/bash
#монтирую ftp с помощью curlftp
/usr/bin/curlftpfs ftp://user:password@ftp.server.ru/../path/EKT /net/ftp/
#делаю бэкап предыдущего содержимого, распакованного неделю назад
for i in /net/domain/DDD/OLGA/Publication/*tif; do /bin/mv -v $i $i.bak;done
#find находит нужные файлы и распаковывает сразу в "расшаренный" каталог windows-сервера
/usr/bin/find /net/ftp/ -type f -atime -3 -exec /usr/bin/unzip '{}' -d /net/domain/DDD/OLGA/Publication/ \;
#отключаю ftp
/usr/bin/fusermount -u /net/ftp


Не знаю, нашел бы я когда-нибудь специализированную программу для этих действий.
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: Unix-way в действии

Сообщение t.t »

Вспомнился вдруг маленький, но, на мой взгляд, показательный пример. Такая локальная подзадача: есть список путей к файлам, без пробелов в именах; нужно выбрать из них самый глубокий по уровню вложенности каталогов, а среди файлов одинаковой глубины вложенности -- самый старый. Решение, которое родилось "на ходу" (пишу по памяти, т.к. ни той машины, ни даже полноценного bash + coreutils под рукой нет -- только busybox):

Shell

find ... | xargs ls -l | tr -d ' ' | cut -d ' ' -f 6- | while read i; do set $i echo $(echo $4 | sed 's|/[^/]*|a|g; s/$/z/') $* done | sort -M | tail -1 | cut -d ' ' -f 5


Понимаю, что решение скорее всего не оптимально по многим характеристикам, но на тот момент оно было оптимальным по наиболее важной: время придумывания и реализации.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Unix-way в действии

Сообщение drBatty »

t.t писал(а):
16.11.2009 12:34
Понимаю, что решение скорее всего не оптимально по многим характеристикам, но на тот момент оно было оптимальным по наиболее важной: время придумывания и реализации.

честно говоря - лень думать, точнее сейчас очень мало времени. это задачка на на 5 минут, а наверное на 50, как минимум (для меня). Я примерный план набросаю:
1) анализируем текст только с помощью sed.
2) ничего не выводим, а только ищем в строке паттерн вроде ([^/]+\/)+
3) грузим это в holdspase.
4)пункты 2 и 3 только для первой строки.
5)для других строк отрезаем от holdspace и от строки паттерн ([^/]+\/), до тех пор, пока что-то не кончится (для единообразия добавим / в конце каждого пути, если его там нет).
6)если кончилась строка - ничего не делаем
7)если кончился holdspace - значит путь длиннее. - сохраняем этот путь.

Есть более простой вариант - сразу заменить

Код: Выделить всё

XXX/CCC/TTT/QQQQ/RR/ например на
№№№№№

т.е. пять подкатологов на пять "№", а потом просто найти в этой строке "№№№№№" holdspace, если найдётся - значит там записано например "№№№№№№№№№№№№№№№№№№№" - ничего не делаем. если нет, то наверное "№№№№" или ещё что-то короче - сохраняем. ищем и вырезаем так:

Код: Выделить всё

G
# теперь область удержания и строка соединились например в
# "№№\n№№№№№", далее так
s/(№+)\n\1/ /
# мы вырезали лишние № и заменили их пробелом, теперь
# если замены НЕБЫЛО, то мы сохраняем новый паттерн.
t
# правда мы его убили, потому восстановим:
G
s/\n//
h

ну примерно такая схема. надо доделать и отладить конечно.

ЗЫЖ да, с переходами в sed сплошная кривизна, потому превращение путей в № проще сделать одной sed, а вот анализ - следующей. Старый путь можно хранить в чётных строках, а обработанный в нечётных, тогда нечётные можно отфильтровать адресным выражением 1~2. ну подумаю на досуге...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Unix-way в действии

Сообщение drBatty »

Я скачиваю разные серии мулом, и все они имеют разные имена. Этот однострок приводит их к одному виду:

Код: Выделить всё

$ ls | sed -rn '/sled/I{s/^Sled\.[0-9]+\.avi$/->&/;t;s/^sled[^0-9]*([0-9]+).*/mv -v & Sled.\1.avi/iep}'
`Sled----341lflfdl.avi' -> `Sled.341.avi'


В оригинале ампресанд (&) был в кавычках - что-бы нормально работало и с файлами, которые содержат спец-символы внутри.

кстати, у меня полно маленьких простых примеров. может кому-то пригодится.

"у меня" - я личность довольно известная, потому вы всегда сможете меня найти. По некоторым причинам (слишком большой любви к Свободе, граничащей с анархией и вседозволенностью) я не буду давать свой адрес - ищущие да обрящут.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Unix-way в действии

Сообщение watashiwa_daredeska »

Что-то тема заглохла :)

t.t писал(а):
16.11.2009 12:34
Понимаю, что решение скорее всего не оптимально по многим характеристикам, но на тот момент оно было оптимальным по наиболее важной: время придумывания и реализации.

Shell

find . -type f -printf '%P %A@ %P\n' \ | sed -r 's%^[^/ ]*%-1%;:a;s%^(-?1*)/[^/ ]*%\11%;ta' \ | sort -n | head -n1 | cut -d' ' -f3
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: Unix-way в действии

Сообщение t.t »

watashiwa_daredeska писал(а):
24.04.2010 21:57
Что-то тема заглохла :)
Да, спасибо, что напомнил.

watashiwa_daredeska писал(а):
24.04.2010 21:57
t.t писал(а):
16.11.2009 12:34
Понимаю, что решение скорее всего не оптимально по многим характеристикам, но на тот момент оно было оптимальным по наиболее важной: время придумывания и реализации.

Shell

find . -type f -printf '%P %A@ %P\n' \ | sed -r 's%^[^/ ]*%-1%;:a;s%^(-?1*)/[^/ ]*%\11%;ta' \ | sort -n | head -n1 | cut -d' ' -f3
Да, подтверждает как моё предположение о неоптимальности изначального решения, так и широко известный факт, что любая задача имеет множество, вообще говоря, непохожих друг на друга решений. (:
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Ответить