1. Context

On Linux systems, 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 pipeline. 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 couldn’t force it to be the default because doing so might break some scripts on the machine that assume 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 on others due to version differences.

2. Perl

I went looking online for a solution and saw perl being recommended multiple times. I never used Perl but knew 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 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 tends to be more readable for some one-liners.