1. Context

On a Linux system, grep, sed and awk are old and ubiquitous tools.

They are often considered standard, and relied upon by users.

However, I recently encountered a case where sed does not run the same across Unix systems.

1.1. Problem

At work, as part of a tool running on the local machine of the developer, and in the CI/CD pipeline, I needed to remove some lines from a file before processing it further.

I reached for sed, and tested the command successfully on the CI/CD pipeline:

sed -i -e '/xxx/d' file.txt

However, while testing on my Mac laptop, it couldn’t run, unless I provided an empty argument to -i:

sed -i '' -e '/xxx/d' file.txt

But, this would no longer run in the CI/CD.

It turns out that the GNU sed, and the Mac OS sed do not behave exactly the same, in many different ways.

The sed implementation on Mac comes from a BSD, and so BSD systems are also affected (depending on the version of the system).

1.2. Other issues

At first, I thought about installing GNU sed on Mac, but I cannot force it to be the default, because doing so may break some scripts on the machine that assume that sed is the default one.

This also reminded me of a time when I met some issues with GNU grep sometimes not having the -P option for better regular expression support on some systems in the company, while present in others (due to versions differences).

2. Perl

I went looking online for a solution, and I saw perl being recommended multiple time.

I never used Perl, but I know it was ubiquitous, because it was once very popular for web applications. It also brought powerful regular expressions that we take for granted in other systems (like that -P option of grep meaning Perl).

For one liners, I thought I could give it a try (Perl being pre-installed on Mac OS, and Perl ensuring a very strong compatibility from one version to another).

2.1. grep, sed and awk: Perl Equivalents

Print only lines that match a pattern
# Perl
perl -ne 'print if /pattern/' file.txt

# Linux
grep -P 'pattern' file.txt
Print only lines that do NOT match a pattern
# Perl
perl -ne 'print if not /pattern/' file.txt

# Linux
grep -P -v 'pattern' file.txt
Delete lines in a file matching a pattern
# Perl
perl -i -ne 'print if not /pattern/' file.txt

# Linux
sed -i -e '/pattern/d' file.txt
Replace pattern in file
# Perl
perl -i -ne 's/pattern/replacement/g; print' file.txt

# Linux
sed -i -e 's/pattern/replacement/g' file.txt
Print only a column
# Perl
ps aux | perl -a -ne 'print $F[1],"\n"'

# Linux
ps aux | awk '{ print $2 }'
Print matches in a file
# Perl
perl -ne '/(pattern)/ and print $1, "\n"' file.txt

# Linux
grep -P -o 'pattern' file.txt
Counting number of lines
# Perl
ps aux | perl -ne 'END { print $. }'

# Linux
ps aux | wc -l

3. Conclusion

After a short learning curve, it turns out that Perl works the same across systems, and tend to be more readable for some one-liners.