I often work with lists of files in Unix. Usually those lists are generated with find
. The other day, I had a list and I had deleted a lot of unwanted entries from the list, which I usually do on-the-fly in vim
as I see things I don’t want to include, I’ll run a :g?/\.svn/?d
, for example, to delete all files with /.svn/
in their path.
After a bit of work, I realized I had directories in the list, which I did not want. If I had had presence of mind to start with, I could have done something like find . ! -type d
but I don’t want to start over and have to make all the edits again.
Perl to the rescue in the form of a one-liner!
Starting with this sample file ~/a.in
:
. ./fruit ./fruit/apple.txt ./fruit/banana.txt ./jewels ./jewels/diamond.txt ./jewels/ruby.txt ./vegetables ./vegetables/carrots.txt
I run this:
$ perl -lne '-d || print' ~/a.in >~/a.out
Which gives me:
$ cat ~/a.out ./fruit/apple.txt ./fruit/banana.txt ./jewels/diamond.txt ./jewels/ruby.txt ./vegetables/carrots.txt
Arguments are as follows (see perl --help
for more detailed information):
* l
automatically chomp
each line, removing the newline at the end of it
* n
puts the code inside a while() { ... }
loop
* e
execute the next argument as code (which goes inside while
loop)
* '-d || print'
the current line is a directory OR (||
) print
it
* ~/a.in
the input file which contains the names of files and directories
* >~/a.out
send output to file ~/a.out
If you’re very confident, you can run:
$ perl -i -lne '-d || print' ~/a.in
The switch -i
tells perl
to edit the file in place. There are options to back up the original file if you’re less confident – see perl --help