sed
sed и локализаци или "почему .* не работает так как надо"
Краткий ликбез по меткам и (без)условным переходам в sed
sed во многом аналогичен специфичному диалекту ассемблера. Он предоставляет для работы два регистра - "pattern space" и "hold space". Во многом эти регистры аналогичны регистрам обычного процессора, типа EAX или EBX x86-ой архитектуры, но специфичных тем, что хранят они не некое 32-битное число, а некую строку текста. В любой конкретный момент возможна работа только с одним регистром, являющимся текущим. Переключать текущий регистр можно с помощью команды x. Так же, sed предоставляет механизм "меток", тоже аналогичный lable'ам ассемблеров, включая возможность условного и безусловного переходов к заданным меткам, что делает sed тьюринг-полным языком программирования.
Работают они следующим образом:
Создание метки:
:имяметки
Метка создаётся посредством оператора : со следующим именем метки. Именно это имя будет использоваться при условных и безусловных переходах
Переходы:
Безусловный:
bимяметки
Разворачиваем таблицы в текст внутри html
Понадобилось сделать из html-книги fb2. Дело давно известное, инструменты есть (OOoFbTools).
Но, как оказалось, FBReader на моей моторолле не понимает таблицы, коих в книге оказалось 51 штука.
Итак, задача: превратить внутри html все таблицы (например, <table><tr><td>blah</td><td>blah-2</td></tr></table>) в текст (например, <p><p>   blah     blah-2   </p></p>)
Действуем:
cat book.htm | sed 's/<TABLE.*>/<P>/g; s/<\/TABLE>/<\/P>/g; s/<TR>/<P>/g; s/<\/TR>/<\/P>/g; s/<\/\?TD>/\ /g' > book-notables.htm
P.S. Программистов с праздником ;)
Пример замены n-го появления строки в файле
Задача была озвучена так:
20:19 < todd_dsm> hey all, I have 1 file to modify (httpd.conf) I need to change the 2nd of for occurrences of "AllowOverride None". Is there a way do change the 2nd occurrence and leave 1,3, and 4 untouched?
Примерный перевод
У меня есть httpd.conf. Мне надо заменить второе появление в файле "AllowOverride None". Есть возможность заменить второе появление, не тронув первое, третье и четвертое?
Ответ:
Пример заменяет второе появление "AllowOverride None" на "replace".
$ printf "AllowOverride None\nAllowOverride None\nAllowOverride None\nAllowOverride None\n" |
awk '/AllowOverride None/ && (++i == 2) {print "replace";next}{print}'На sed
$ printf "AllowOverride None\nAllowOverride None\nAllowOverride None\nAllowOverride None\n" |
sed -e '/AllowOverride None/{x;/^1$/{x;s/.*/replace/;x};s/$/1/;x}'Потоковое редактирование на месте с помощью ed
Для того что бы заменить строчку в файле часто используется sed с ключиком -i.
Но не все знают что sed на самом деле создает копию файла и заменяет его на оригинал (не лишнее будет прочитать в man sed что на самом деле обозначает -i).
Проверить это можно так:
$ echo 1 > z.txt && ls -li z.txt && sed -i 'i1' z.txt && ls -li z.txt && rm z.txt 5290353 -rw-rw-r-- 1 ramok ramok 2 Апр 7 13:00 z.txt 5290354 -rw-rw-r-- 1 ramok ramok 4 Апр 7 13:00 z.txt
Здесь создается пустой текстовый файл, выводится номер его inode, затем с помощью sed добавляется '1', и снова выводится inode файла.
Видно что inode изменился.
При этом копия файла создается в текущей директории. Увидеть это можно так:
$ echo 1 > z.txt && ls -li z.txt && strace sed -i 'i1' z.txt 2>&1 | grep open && ls -li z.txt && rm z.txt
879149 -rw-rw-r-- 1 komar komar 2 Апр 7 13:06 z.txt
open("/etc/ld.so.cache", O_RDONLY) = 3Выкачка обоев с сайта космического телескопа Hubble
NASA выкладывает в общественный доступ удивительной красоты снимки космоса сделанные космическим телескопом Hubble.
Выбираем сначала свое разрешение для обоев, смотрим какие есть.
$ wget -qO - http://hubblesite.org/gallery/wallpaper/pr2003001a/ |
sed -ne 's/.*id="wallpaper-\([^"]*\).*/\1/;T;N;s,\(.*\)\n.*/\([^_]*\)_wallpaper/".*,export RESOLUTION=\2 # for resolution \1,p'
export RESOLUTION=640 # for resolution 640x480
export RESOLUTION=800 # for resolution 800x600
export RESOLUTION=1024 # for resolution 1024x768
export RESOLUTION=1280 # for resolution 1280x1024
export RESOLUTION=1152x864 # for resolution 1152x864
export RESOLUTION=1280x768 # for resolution 1280x768
export RESOLUTION=1280x800 # for resolution 1280x800
export RESOLUTION=1280x960 # for resolution 1280x960
export RESOLUTION=1440x960 # for resolution 1440x960Как фильтровать абзацы
Иногда возникает необходимость отфильтровать только те абзацы в тексте, которые содержат какое либо слово или строку.
Под абзацами подразумевается текст отделенный от остального текста пустой строкой.
Практический пример:
при настройке мультимедийных клавиш, xev выводит очень быстро, очень много текста. Хочется фильтровать только описание событий связанных с определенными клавишами. Например пусть это будет XF86Forward и XF86Back.
Собственно пример команды
$ xev | sed -ne 'H;$bz;/^$/{:z;g;/XF86Forward\|XF86Back/p;s/.*//;x}'Запускаем это и нажимаем все мультимедийные клавиши в поисках нужных.
Как это работает:
1. Накапливаем в буфере (hold space) абзац
2. Если находим признак окончания абзаца (в нашем случае - пустая строка) или это последняя строка, забираем из буфера накопленный.
2.1 Проверяем если нужные слова в абзаце. Если есть - печатаем абзац.
2.2. Стираем обработаный абзац.
Cамораспаковывающийся архив
Привожу заготовку для скрипта который содержит в себе архив.
#!/bin/sh sed -e '1,/^END_OF_SCRIPT$/d' $0 | base64 -d | tar -xj exit END_OF_SCRIPT
после слова "END_OF_SCRIPT" можно запулять какой нибудь tar.bz2 архивчег. например так
$ cat myrch.tar.bz2 | base64 >> scriptname.shв зависимости от того какой архив и как вы его туда запулили меняется также и комманды распаковки.
авторство скрипта пренадлежит ramok
Перевод букв в верхний/нижний регистр с помощью sed
Задача: Хочется перевести текст в верхний или нижний регистр с помощью sed. Делаем несколько попыток.
Заменить повторяющиеся пустые строки на одну пустую строку
Допустим у вас есть файл в котором множество повторяющихся пустых строк. А вам
хотелось бы повторяющиеся пустые строки заменить на одну пустую строку (что бы
было легче читать например).
sed -e ':a;/^$/N;/\n$/{D;ba}' file.txtПримечание:
В *BSD системах, однострочник придется оформить так:
sed -e :a -e '/^$/N;/\n$/{D;ba' -e '}' file.txtтак как после имени метки и перед } необходим перевод строки.
Объяснение как это работает
Краткий справочник по массовому переименовыванию файлов :-)
Иногда нужно производить массовые переименования файлов. Изучая командную строку юникса когда то, меня удивило отсутствие такой приятной возможности в DOS как массовые переименовывания файлов (помню было что то типа copy *.c *.bak).
1. По первому разу я просто в vi создавал множество команд mv производящие нужные действия. Самый очевидный, и самый трудоемкий путь Ж:-)
2. Позже я начал разбираться с командной строкой юникса и мог запрограммировать массовые переименования.
for i in *.c; do
mv $i `echo $i | sed 's/\.c$/.bak/'`
doneИнформер в консоли
Этот однострочник забирает и чистит "погодный информер" с gismeteo.ru, и может использоваться например в conky или в .bashrc
curl -s http://informer.gismeteo.ru/text/33345-1.JS|sed -e 's/^.*write("//g'|\ sed -e 's/\(<[^>]*>\)\+/\n/g'|sed -e 's/");//g'|iconv -f cp1251 -t UTF-8
Как перевести имя файла в нижний или верхний регистр
Используя этот скрипт взятый из info sed
все что ниже можно просто выделить и скопировать в шел
cat << END_SCRIPT > move-to-lower #! /bin/sh # rename files to lower/upper case... # # usage: # move-to-lower * # move-to-upper * # or # move-to-lower -R . # move-to-upper -R . # help() { cat << eof Usage: $0 [-n] [-r] [-h] files... -n do nothing, only see what would be done -R recursive (use find) -h this message files files to remap to lower case Examples: $0 -n * (see if everything is ok, then...) $0 * $0 -R . eof } apply_cmd='sh' finder='echo "$@" | tr " " "\n"' files_only= while : do case "$1" in -n) apply_cmd='cat' ;; -R) finder='find "$@" -type f';; -h) help ; exit 1 ;; *) break ;; esac shift done if [ -z "$1" ]; then echo Usage: $0 [-h] [-n] [-r] files... exit 1 fi
Перевод шеснадцатиричного представления IP в стандартную форму в конс
перевод hex IP -> dec IP
1) bash only by ams
$ i=ffffffc0; echo $((0x${i:0:2})).$((0x${i:2:2})).$((0x${i:4:2})).$((0x${i:6:2}))2) так короче но $[] dericated
$ i=ffffffc0; echo $[0x${i:0:2}].$[0x${i:2:2}].$[0x${i:4:2}].$[0x${i:6:2}]3) тоже вроде только для bash как имеющий опцию -n в read
$ echo ffffffc0 | while read -n 2 D; do [ -z $D ] || printf "%d." 0x$D; done; echo4) sh+sed
$ printf "%d.%d.%d.%d\n" `echo ffffffc0 | sed 's/\(..\)\(..\)\(..\)\(..\)/0x\1 0x\2 0x\3 0x\4/'`5) тоже но немного разбираясь в sed Ж:-)
$ printf "%d.%d.%d.%d\n" `echo ffffffc0 | sed 's/\(..\)/0x\1 /g'`6) printf only by ams. но это только смотреть, пайпы не пройдут Ж:-)
Немного магии sed Ж:-)
Несколько забавных примеров:
$ echo metric | sed -e strictest metes $ echo dated | sed -e statement demented $ echo routing | sed -e stoutest resting $ echo face | sed -e secede fade $ echo ontology | sed -e sentence oncology
Для тех кто не понял подсказка Ж:-)
SUSv3 по этому поводу:
"Any character other than backslash or can be used instead of
a slash to delimit the BRE and the replacement."


