I'd like to execute a shell script for some pre-configuration tasks on the first boot. I found systemd.run like this in the cmdline.txt on the boot partition:

console=serial0,115200 console=tty1 root=PARTUUID=d2b047ad-02 rootfstype=ext4 fsck.repair=no rootwait systemd.run=/boot/my_init.sh

During the troubleshooting, I minimized my_init.sh to just return 0:

exit 0

But this minimal example still doesn't work: During the boot, the screen went off and only the red power LED keeps being active. Since the output logs are written fast, I made a video to see if there is any usefull output:

enter image description here

Starting File System Check is the last line, then the screen went black. I found this documentation which indicates that shutting down is the default action. It seems a bit odd to me that this happens before a file system check without any log messages, but it could explain this behavior.

I also tried systemd.run=/boot/ulabs_image2card_init.sh systemd.run_success_action=reboot without any difference. After adding systemd.run_failure_action=reboot the Pi was rebooted. So it seems something went wrong, but what? The minimal script just return 0 which should indicate success. Setting the execute bit doesn't help, too.

2 Answers 2


Add the shell script to /boot/tasks.sh on the micro SD card.

The first boot with default settings is recommended to resize the disk partition.

Wait until the green light stops blinking during first boot.

Before the second boot, add this in /boot/loader on the micro SD card.

mount -t tmpfs tmp /run
mkdir -p /run/systemd
mount / -o remount,rw
sed -i 's| init=.*||' /boot/cmdline.txt
sudo cp /boot/tasks.sh /home/pi/tasks.sh
sudo chmod +x /home/pi/tasks.sh
sudo cd /home/pi/ && sudo ./tasks.sh
echo 1 > /proc/sys/kernel/sysrq
umount /boot
mount / -o remount,rw
echo b > /proc/sysrq-trigger
sleep 10
exit 0

To make this execute on each boot, remove sed -i 's| init=.*||' /boot/cmdline.txt.

Then, add this line to the end of /boot/cmdline.txt.

init=/bin/bash -c "mount -t proc proc /proc; mount -t sysfs sys /sys; mount /boot; source /boot/loader"

The tasks.sh script will be executed on boot and removed afterwards.


It turned out that the script uses CR LF (\r\n). Since I currently used VS, I was running Windows instead of Linux without remembering that Windows uses CRLF as default, where Linux/Unix uses just LF (\n) without CR.

I couldn't find a way to get more logs. It become clear when removing the directives from the cmdline.txt and tried to execute the script manually. After using LF instead of CRLF, the script was called and then the PI rebooted when having

systemd.run=/boot/ulabs_image2card_init.sh systemd.run_success_action=reboot

set without systemd.run_failure_action=reboot. To give it more sense, we need to add sed -i 's| systemd.run.*||g' /boot/cmdline.txt in our init script. This removes the systemd.run directives from the kernel parameters after the first boot, so there is no endless boot-loop.

For me this seems much easier than a modified approach of Raspbian or overriding the init parameter. I think overriding the ini parameter is a more general approach, which is good for either getting a deeper understanding how the boot process works or if systemd is not avaliable (e.g. on Alpine). But since Debian has switched to init.d a while ago, I'd prefer this approach. Using systemd.run makes our init script much smaller, because we don't have to care about things like mounting and unmounting disks.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.