0

I'm having difficulty using variables inside a perl command.

What I'm trying to do is convert a perl command to a bash script. The bash script would be used to search any given file for a given regex pattern. The bash script should first request which file to open and then request the regex pattern.

I already have a working command line and everything I tried to convert it to a bash script didn't work... I don't have much experience with command lines and bash script and I have read a lot on the internet and nothing seems to work.

#!/bin/bash

read -p "Enter the path to the file : " file_path
read -p "Enter the regular expression : " reg_exp

perl -ln0777e 'my $count=1; print "===================== RESULTS ====================="; while (/'"${reg_exp}"'/g) {printf("[%02d] Offset: 0x%x length: %dB\n     Position: %d to %d \n     Hex match: %s\n     Original: %s\n", $count++, $-[ 0 ], length $1, $-[ 0 ], $-[ 0 ] + length( $1 ) - 1, unpack("H*",$1), $1)}' "${file_path}"

When I try to use the variables inside the regex, it doesn't seem to be interpreted as a variable...

This is what the result should look like: enter image description here

My command line is this:

perl -ln0777e 'my $count=1; print "===================== RESULTS ====================="; while (/REGULAR_EXPRESSION/g) {printf("[%02d] Offset: 0x%x length: %dB\n     Position: %d to %d \n     Hex match: %s\n     Original: %s\n", $count++, $-[ 0 ], length $1, $-[ 0 ], $-[ 0 ] + length( $1 ) - 1, unpack("H*",$1), $1)}' SOURCE_FILE

SOLUTION:

Here is the working code that I came up with. Thank you Ikegami for your help!

#!/bin/bash
read -rp "Enter the path to the file : " file_path
read -rp "Enter the regular expression : " reg_exp

perl -sn0777e'
   while (/$reg_exp/g) {
      printf "[%1\$02d] Matched %2\$d bytes from position %3\$d (0x%3\$x) to %4\$d (0x%4\$x)\n",
         ++$count, $+[0]-$-[0], $-[0], $+[0]-1;
      printf "     Hex: %s\n", unpack("H*", $&);
      printf "     Match: %s\n", $&; 
   }
' -- -reg_exp="${reg_exp}" -- "${file_path}"
0

1 Answer 1

3

The snippet attempts to generate Perl code, but it does so incorrectly. This is known as a code injection bug.

The easiest way to fix this is to avoid generating Perl code at all. This other answer suggests ways to pass data to a Perl one-liner. We'll use the second one here.

perl -sn0777e'
   while (/$reg_exp/g) {
      printf "[%1\$02d] Matched %2\$d bytes from position %3\$d (0x%3\$x) to %4\$d (0x%4\$x)\n",
         ++$count, $+[0]-$-[0], $-[0], $+[0]-1;
      printf "Match: %s\n", $&; 
      printf "Hex: %s\n", unpack("H*", $&);
   }
' -- -reg_exp="$reg_exp" -- "$file_path"

I made a few changes:

  • I removed the (unverified) expectation for the pattern to be embedded in a capture by using a combination of $& and $+[0] instead of $1 (and length($1)).
  • I made the output cleaner and more self-consistent.
  • I made the code more readable.

Note that you can get weird output for 0-characters matches (e.g. 0 bytes from position 6 to 5). For this reason, an exclusive end position is often used ($+[0] instead of $+[0]-1). I left this unchanged since 0-character matches are unlikely and inclusive positions are often used as well.

Sign up to request clarification or add additional context in comments.

4 Comments

If I insert the values directly instead of the variables, this code works... But when using the variables, it doesn't produce the expected result. It's as if it can't produce a command line dynamically.
Right, and I explained why that was the case, I explained how to fix it, and I provided the fix for it. (There was a small problem with the output I just fixed.)
Okay... I have found what went wrong! :D Apparently, using "read -p" eats the backslashed characters... I had to use "read -rp" in order to keep them.
And now you know why it's important to also provide inputs when demonstrating a problem. Note that you still need the fix I provided

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.