Был занят, занимался самообразованием, т.к. почувствовал что погряз в одном и том же. Расширяю кругозор, узнаю новое, к чему то стремлюсь, это очень интересно и занимает очень много времени.
Теперь по делу.
Операционная система у меня ubuntu ++ постоянно по работе приходится сидеть в консоли. Очень часто возникает задача, быстро по шаблону поменять что то в файле. Ответ на вскидку = sed. В свое время я читал про него, но понял что при помощи perl могу делать то же самое. Прошло время, sed я забыл совершенно, а вот perl тоже стал забываться, и я постоянно не могу найти пример однострочных скриптов.
Теперь по порядку.
Задача:
Дано.
Есть файл xx.txt в котором лежат числа от 1-го до 5-ти, каждое число, новая строка.
cd@laptop:~/data/tmp$ cat xx.xx
1
2
3
4
5
Нужно:
Хочется заменить все вхождения строки 3 на что то свое, пусть это будет строка "hello"
Решение:
cd@laptop:~/data/tmp$ perl -ig -ne 's/3/hello/;print $_; ' xx.xx
cd@laptop:~/data/tmp$ cat xx.xx
1
2
hello
4
5
Или
cd@laptop:~/data/tmp$ perl -ig -pe 's/3/hello/; ' xx.xx
cd@laptop:~/data/tmp$ cat xx.xx
1
2
hello
4
5
cd@cd-acer:~/data/tmp$ ls *g
9.jpg xx.xxg
Объяснение.
perl позволяет запускать однострочные скрипты, не создавая файл с кодом скрипта.
Пример:
cd@laptop:~/data/tmp$ perl -e 'print "test\n"'
test
cd@laptop:~/data/tmp$
За это отвечает опция -e после которой идет код для выполнения.
Однострочные скрипты, после кода, могут принимать параметром файл, а также, можно заставить выполнять код указанный -e для каждой строки.
Пример:
cd@laptop:~/data/tmp$ perl -ne "print ;" xx.xx
1
2
hello
4
5
Т.е. в данном случае мы попросили перл, выполнить распечатку строки по умолчанию, а т.к. была указана опция -n то это команда применялась к каждой строке файла xx.xx, т.е. получили cat
Также существует параметр -p, который после выполнения кода распечатывает строку. Т.е. логично что команда вида
perl -ne "dosmth; print $_;" file
будет аналогична
perl -pe "dosmth" file
Ну а теперь завершая. Мы добились того, что можем выполнять любые операции над каждой строкой в файле, и печатать это в stdout, однако первоначальная постановка задачи, звучала как замена строк в файле на лету. Именно для этого и существует опция -i
т.е.
perl -i -pe "dosmth" file
выполнит код dosmth для отдельно взятой строки и заменит ее в указанном файле.
опция -i может принимать необязательный параметр, и тогда, скрипт перед началом работы сделает backup копию файла
Пример.
cd@laptop:~/data/tmp/1$ perl -ibak -ne 'print;' 1.txt
cd@laptop:~/data/tmp/1$ ls
1.txt 1.txtbak
cd@laptop:~/data/tmp/1$ cat 1.txt
1
2
3
cdlaptop:~/data/tmp/1$ cat 1.txtbak
1
2
3
cd@laptop:~/data/tmp/1$
Теперь само решение должно быть понятно, а также понятно почему я привел два варианта.
Upd:
Появилась простая задачка, в одном из конфигов нужно увеличивать на единицу одно из значений, пусть условно это будет номер билда.
Возьмем пример файла конфига
cd:$ cat config
Key1 Value2
build=projectname.005
one more line
Допустим нам нужно получить такой же конфиг но с build=projectnam.006
perl -i -pe 's/(projectname\.)(\d+)/sprintf("%s%03d", $1, $2+1)/e' config
Пояснения.
-i -pe объяснялось выше.
Что изменилось? В конце регулярного выражения добавился флаг e, который означает что правая часть выражения будет выполняться как код perl и только после выполнения результат подставится для замены.
Можно было бы конечно сделать что то вроде
perl -pe 's/(projectname\.)(\d+)/$1 . ($2+1)/e' config
Key1 Value2
build=projectname.6
one more line
! опция -i была убрана, я хотел чтобы файл не менялся, а результат был в output
Как видим пропадают два ведущих нуля, именно поэтому была использована функция sprintf