//Tips tagged perl
Replace toto by foo in all file found by find.
It make a backup $file.bak
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
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.
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 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
Find and replace recursively over several files:
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.
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.
Rename a lot of files at once:
Change 'aaa' and 'bbb' to what you want to find and replace in the filename
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
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.
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
#!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
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
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:
Usage:
Then you want to resync and upgrade all existing Tracs:
trac-mass-upgrade.sh:
Usage:
Now you have everything in order.
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.
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++; } }
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},'.')"Print a file until a regular expression is matched.
cat file.txt | perl -pe "exit if(/Last line we want/)"

