2

Like vi perhaps?

My perl equivalent is:

grep -Po '(?<=^.L.........\s).*(?=\s->\s)' rsync_itemized.log

Which finds all the symlink modifications and outputs the filename part. Obviously, I can use awk:

awk '$1 ~ /^.L........./ { print $2 }' rsync_itemized.log

But I was wondering if greps native regex engine supports it.

Craig
  • 4,268
  • 4
  • 36
  • 53
  • Apparently not, per [this](http://stackoverflow.com/a/9198987/1681480), which you probably already saw. – beroe Oct 18 '13 at 16:32
  • Hadn't seen that, no. I actually wrote some unit tests using the -P option, but since the unittest started to run tests that could potentially remove things from the root file system, I switched to using a chroot for the environment the software will run in. That, unfortunately had no grep without perl support. So I was merely looking for a cheap way to change my existing expressions without having to change much else. Thanks though. – Craig Oct 18 '13 at 18:18
  • I see. Can you install things in chroot? `ack` grep apparently will do look-aheads. – beroe Oct 18 '13 at 18:23
  • Not trivially, since its unpacked from an image built somewhere else. I'll use `awk` since I have that available. – Craig Oct 18 '13 at 18:24
  • ack is specifically designed to be able to be installed as a single text file. You can download the single Perl program and put it anywhere on your system you want. See http://beyondgrep.com/install/ for details. – Andy Lester Dec 02 '15 at 18:03

1 Answers1

1

A few notes:

  • grep -P uses libpcre, a compiled library (written in C, not perl) that is perl-compatible
  • Your awk command won't work if there is a space in the file name

This sed command will work a little better:

sed '/^.L......... /!d; s///; / -> .*/!d; s///'

This deletes all lines that do not match the first regex, then removes the matching portion of the remaining lines, then does the same for the second regex, leaving you with the text in the middle. Since regexps are greedy, the second regex will turn a -> b -> c into a even though you wanted a -> b, so this isn't a perfect solution either.

Perhaps you can use perl directly (I assume you're on a system for which grep was compiled without the libpcre library and therefore can't do -P but perhaps you still have access to perl):

perl -ne '/^.L.........\s(.*)\s->\s/ and print "$1\n"'

This time, greediness works in our favor (regexps are evaluated left to right) and you'll correctly extract a file named a -> b that is symlinked to c.

If you have GNU sed (nearly any Linux system), you can mimic that logic:

sed '/^.L.........\s\(.*\)\s->\s.*/!d; s//\1/'

 

But I haven't technically answered your question, which was about using grep without -P. grep uses basic and extended POSIX regular expressions (BRE and ERE). Even ERE can't do what you're looking for, so the quick answer is that you cannot do this in a single grep command without -P. You might be able to do it with multiple grep commands, but it would be extremely ugly and I'm leaning on saying you actually cannot do it without look-arounds or text replacement, neither of which are available in BRE or ERE.

Adam Katz
  • 14,455
  • 5
  • 68
  • 83