profile picture

Michael Stapelberg

grep(1) with line continuations (2013)

published 2013-07-27, last modified 2018-03-23
Edit Icon

For some rather advanced isolation and automation work I am currently doing with Debian Code Search I needed to modify the ExecStart= line of a systemd service file programmatically.

The recommended interface for programmatically querying service file properties is systemctl show -p ExecStart foo.service, but with the ExecStart= property in particular, the output cannot be parsed well:

$ systemctl show -p ExecStart dcs-batch0-source-backend.service --no-pager
ExecStart={ path=/usr/bin/source-backend ; argv[]=/usr/bin/source-backend -unpacked_path=/dcs/unpacked-new/ -listen_address=localhost:30000 ; ignore_errors=no ; start_time=[Sat 2013-07-27 19:58:23 CEST] ; stop_time=[n/a] ; pid=12428 ; code=(null) ; status=0/0 }

Therefore, I decided to extract the ExecStart= line from the service file directly instead of querying it from systemd. One might think that a simple grep(1) call like grep '^ExecStart=' foo.service would be enough, but systemd supports line continuations in the service file syntax and I make use of that in my service files.

It is a well-known truth that whenever grep(1) fails, perl(1) saves the day:

perl -nlE 'say if /^ExecStart=.*[^\\]$/ || /^ExecStart=/ .. /[^\\]$/' < /lib/systemd/system/sudo.service
ExecStart=/usr/bin/find /var/lib/sudo -exec /usr/bin/touch -t 198501010000 '{}' \073
perl -nlE 'say if /^ExecStart=.*[^\\]$/ || /^ExecStart=/ .. /[^\\]$/' < /run/systemd/system/dcs-batch0-source-backend.service
ExecStart=/usr/bin/source-backend \
    -unpacked_path=/dcs/unpacked/ \