//Tips tagged perl
Latest tips by RSS
Click here to subscribe
Follow Shell-Fu on Twitter
Click here to follow
Follow Shell-Fu on identi.ca
Click here to follow
Find and replace recursively over several files:
perl -pi.bak -e "s/Bob/Steve/gi" *.html

The '.bak' will create copies of your original files with the .bak extension added incase of mistakes. Be careful of running this twice though as the backups will get overwritten.


View Comments »



You can use diff to see the differences between two files, but it can be useful to see what is the same and more clearly how they differ. This is where comm comes in useful.

comm tells you what information is common to two lists and what information appears uniquely in one or the other.

$ find . -type f -print -exec cat {} \;
./1.txt
a
b
c
./2.txt
a
c
e

$ comm 1.txt 2.txt 
                a
b
                c
        e


The first column shows lines only in the first file, the second column lines from the second file and the third column lines from both.

This can be made easier still by adding a bit of perl:
$ comm 1.txt 2.txt | perl -pe 's/^/1: /g;s/1: \t/2: /g;s/2: \t/A: /g;' | sort
1: b
2: e
A: a
A: c


View Comments »

Rename a lot of files at once:
find . | perl -ne'chomp; next unless -e; $oldname = $_; s/aaa/bbb/; next if -e; rename $oldname, $_'

Change 'aaa' and 'bbb' to what you want to find and replace in the filename


View Comments »

find . -name *whatyouwant* -exec perl -pi.bak -e 's/toto/foo/g' {} \;

Replace toto by foo in all file found by find.
It make a backup $file.bak


View Comments »

I've long been frustrated by the lack of an interactive perl shell, where I can enter commands and see the results immediately. Yes, I have tried the perl debugger.

#!perl

use strict;
no strict 'vars';
no strict 'refs';
use warnings;

use Data::Dumper;
$Data::Dumper::Indent--;

$| = 1;

# an alias for exit()
sub quit { exit; }

my ($ver,$maj,$min) = ($] =~ /(\d+)\.(\d{3})(\d{3})/);
$maj += 0;
$min += 0;
print +(split '/', $^X)[-1], " $ver.$maj.$min\n";

$, = ',';
$THE_PROMPT = '% ';
print $THE_PROMPT;
while (<>) { print eval; print +($@ || "\n") . $THE_PROMPT };

Caveats:
- you have to enter complete commands on a single line
- because each 'eval'ed line is printed, if the result is undefined you'll get a "Use of uninitialized value" warning

Usage:
- naturally, I create a bash alias for the script
- this is cygwin on winxp, hence the "perl.exe" in the output below

$ alias perlsh='perl ~/bin/perlsh.pl'
$ perlsh
perl.exe 5.10.0
% @l=qw(the quick brown fox jumps over the lazy dog)
the,quick,brown,fox,jumps,over,the,lazy,dog
% @sorted_by_length = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, length]} @l
the,fox,the,dog,over,lazy,quick,brown,jumps


View Comments »

CASE: You've relocated Subversion and Trac repositories to another machine/directories. You don't want to edit n+1 trac.ini files.

You have for example:
/repos/svn-myprojects/my-first-project
/repos/trac-myprojects/my-first-project

/repos/svn-myprojects/my-second-project
/repos/trac-myprojects/my-second-project

...etc...

Change ALL trac.ini repository_dir settings:

trac-mass-repodir-edit.sh:

#!/bin/bash TRACSPATH=$1 REPOPATH=$2 for i in $( find $TRACSPATH -maxdepth 1 -type d | grep -v "^$TRACSPATH\$" ); do BN=`basename $i` INIPATH=$i/conf/trac.ini TMP=$i/conf/trac.ini-temp # Replace repository_dir cat $INIPATH | perl -pe "s@repository_dir = .*@repository_dir = $REPOPATH/$BN@i" > $TMP mv $INIPATH $INIPATH-old && mv $TMP $INIPATH && rm $INIPATH-old done


Usage:
./trac-mass-repodir-edit.sh /repos/trac-myprojects /repos/svn-myprojects


Then you want to resync and upgrade all existing Tracs:

trac-mass-upgrade.sh:
#!/bin/bash

TRACSPATH=$1
REPOPATH=$2

for i in $( find $TRACSPATH -maxdepth 1 -type d | grep -v "^$TRACSPATH\$" ); do
  BN=`basename $i`
  # SVN directory exists
  if [ -d $REPOPATH/$BN ]; then
    echo "Processinc Trac: $BN.."
    trac-admin $i resync
    trac-admin $i upgrade
  fi
done


Usage:
./trac-mass-upgrade.sh /repos/trac-myprojects /repos/svn-myprojects


Now you have everything in order.


View Comments »

Remove all empty directories within the current directory

find . -type d -empty -exec rmdir {} \;

Or another way to do it: perl -MFile::Find -e"finddepth(sub{rmdir},'.')"


View Comments »

This script displays the contents of files (or stdin) in ascii, hexadecimal, decimal, octal, and binary formats.


#!/usr/bin/perl undef $/; # slurp files while( $content = <> ) { $offset = 0; print "OFFSET ASC HEX DEC OCT BIN\n"; while( length $content ) { $n = ord( substr( $content, 0, 1, '' ) ); printf "%08x %c %2x %3u %3o %s\n" , $offset, , ( $n > 0x1f && $n < 0x7f ) ? $n : ord '.', , $n, , $n, , $n, , substr( unpack( "B*", pack( "n", $n ) ), -8 ) ; $offset++; } }



View Comments »

Print a file until a regular expression is matched.
cat file.txt | perl -pe "exit if(/Last line we want/)"


View Comments »




Home Latest Browse Top 25 Random Hall Of Fame Contact Submit