Categories
Terminal Troubleshooting

Fixing sed error “undefined label” and “invalid command code” on MacOS

The life of a programmer is hard. There are moments that we encounter bugs and have absolutely no idea why it’s happening. These occasions challenge our troubleshooting skills. Let’s look at a scenario with sed where the same line of code which works on MacOS won’t work on Linux and vice-versa (I’m testing on Ubuntu) and will yield errors like undefined label or invalid command code on MacOS.

This error happens when you use sed in-place editing, sed --in-place or its shorthand form sed -i, which optionally allows you to create a backup file if you supply an extension. Although the behaviour is the same on Ubuntu and on MacOS, their syntax are different.

Running on Ubuntu

What the man-page of sed tells us about sed -i:

edit files in place (makes backup if SUFFIX supplied)

sed -i[SUFFIX], sed --in-place[=SUFFIX]

Let’s try it on Ubuntu – we create a file with hello world as content, and we will then replace hello by hola. All works perfectly fine:

[email protected]:/var/test$ echo "hello world" > test.txt
[email protected]:/var/test$ cat test.txt                    
hello world
[email protected]:/var/test$ sed -i 's/hello/hola/' test.txt 
[email protected]:/var/test$ cat test.txt 
hola world

Running on MacOS

What the man-page of sed tells us about sed -i:

Edit files in-place, saving backups with the specified extension. If a zero-length extension is given, no backup will be saved. It is not recommended to give a zero-length extension when in-place editing files, as you risk corruption or partial content in situations where disk space is exhausted, etc.

sed -i extension

Let’s try it on MacOS – we create a file with hello world as content, and we will then replace hello by hola. Oops, we have a problem:

▶ echo "hello world" > test.txt                                                        
▶ cat test.txt 
hello world
▶ sed -i 's/hello/hola/' test.txt 
sed: 1: "test.txt": undefined label 'est.txt'

Contrarily to the Ubuntu syntax, MacOS requires you to pass an extension for the backup. The error displayed depends on the first character of the filename you’re using. For example you may get errors like undefined label or invalid command code. You can also pass an empty string if you don’t want any backup. Let’s continue from where we were stuck and try to run sed again with a backup extension first:

▶ cat test.txt                    
hello world
▶ sed -i '.bak' 's/hello/hola/' test.txt                                       
▶ ls
test.txt     test.txt.bak                                                      
▶ cat test.txt
hola world
▶ cat test.txt.bak 
hello world

We can now see that adding the backup extension worked and that we also got a new file created. If you like to live dangerously and do not require the backup file to be created, you pass an empty string to sed -i. We get back to our terminal, delete the backup file and try another replacement. This time we’ll replace hola by hey and not create any backup file:

▶ rm test.txt.bak
▶ ls
test.txt
▶ sed -i '' 's/hola/hey/' test.txt
▶ cat test.txt
hey world
▶ ls
test.txt

It worked! We have done an in-place edit without generating a backup file. The sad thing is that this format will work only on MacOS but not Ubuntu, take note when you’re copying/pasting scripts across different operating systems.