Thunar Custom Actions: Fixing Broken Scripts After Update
Hey guys, ever hit a wall after a system update where something you rely on just stops working? That's exactly what happened to me recently with Thunar's User Custom Actions (UCA) on my CachyOS setup. After updating to Thunar version 4.20.6, my custom actions, which I use all the time for quick file operations, either vanished from the context menu or, even worse, silently failed. This is a huge pain, especially when you've customized your workflow to be super efficient. I spent a good chunk of time digging into this, and I want to share what I found and how I managed to fix it, so hopefully, you won't have to go through the same headache.
My setup is a bit specific – I'm running CachyOS with znver4-optimized packages, which sometimes means things behave a little differently than on a standard Arch or Debian system. The desktop environment is XFCE 4.20, and I've got a few Thunar plugins installed: thunar-archive-plugin, thunar-media-tags-plugin, and thunar-volman. The issue started right after I jumped from Thunar 4.20.5 to 4.20.6, and even a subsequent patch to 4.20.6.1.2 didn't solve it. The core problem seemed to be that Thunar's internal handling of custom actions had gotten seriously messed up. Some actions, like the ever-useful “Open Terminal Here,” just wouldn't show up anymore. For the ones that did appear, running them often resulted in cryptic errors like _: line X: ${base*}: bad substitution. This clearly indicated Thunar was generating some seriously wonky shell code behind the scenes. Filename handling was also a mess, with extensions disappearing and filenames being mangled into strange formats like _1. It felt like Thunar was completely forgetting how to work with basic file operations, which is pretty fundamental for a file manager, right? I tried the usual suspects: reinstalling Thunar and its plugins, downgrading back to 4.20.5 (which gave partial success, hinting at the version change being the trigger), and even nuking configuration and cache files. None of it completely fixed the broken wrapper code or the filename corruption. It was a real puzzle, but by carefully examining the errors and the behavior, I started to piece together what was going wrong.
The Nitty-Gritty: What Was Actually Happening?
So, let's dive a little deeper into the technical mess I was dealing with. The main culprit seemed to be how Thunar was generating the wrapper scripts for our custom actions, especially with the znver4-optimized build. Even if my own scripts were perfectly clean, Thunar was injecting garbage into them. The most glaring issue was the appearance of ${base*} in the generated wrapper code. This is not a valid shell expansion, and it immediately leads to the bad substitution error we were seeing. It’s like Thunar was trying to guess a variable name and failing spectacularly. Another major problem was that sometimes, Thunar would execute these inline UCA scripts using /bin/sh instead of bash, even when I explicitly told it to use bash -c. Now, /bin/sh can be quite different from bash, and it doesn't always support the more advanced parameter expansions that bash does, like ${var%.*} (remove shortest suffix matching .*) or ${var##*.} (remove longest prefix matching *.). When Thunar decided to use sh, these perfectly valid bash constructs would just break, leading to errors and failed actions.
Then there was the weirdness with filenames. The %f argument, which is supposed to represent the selected file, was sometimes passed to the script with unexpected trailing whitespace. Imagine your script getting "example.txt " instead of "example.txt". This seemingly small detail was enough to mess up extension detection logic. If a script tries to split example.txt into name and ext, it might fail or get it wrong, leading to filenames like _1 because the extension part was lost or corrupted. It seems like Thunar was caching some really old, broken UCA metadata. Even when I replaced the uca.xml file with a clean one, Thunar was still executing the old, corrupted wrapper code. This caching mechanism, or lack thereof, was making it really hard to get a clean state. And to top it all off, these issues seemed more pronounced or behaved differently on the znver4 builds compared to generic ones. This suggests that optimizations or specific compiler flags in the znver4 packages might be interacting with Thunar's UCA generation code in unexpected ways, particularly concerning shell fallbacks, how arguments are expanded, and how the internal wrappers are constructed. It’s a complex interplay of factors that made fixing this quite the challenge.
The Troubleshooting Gauntlet: What I Tried (and Didn't Work!)
Okay, so when you're faced with a bug like this, the first instinct is to try all the standard fixes, right? I certainly did. I went through the motions, hoping one of the usual suspects would sort things out. First up was a thorough reinstallation spree. I reinstalled thunar itself, plus the plugins I had installed: thunar-archive-plugin, thunar-media-tags-plugin, and thunar-volman. I also reinstalled exo, which is a dependency that might be involved. No luck. Then, I decided to roll back. I downgraded Thunar from the problematic 4.20.6 back to 4.20.5. This actually got me partially working, which was a good clue that the issue was definitely introduced in the newer version. However, it wasn't a perfect fix, and I wanted to understand why it was broken, not just revert. I tried manually regenerating the uca.xml file, thinking maybe my custom actions file was just corrupted beyond repair. I also went on a clearing spree, deleting specific files and directories that seemed related to Thunar's configuration and cache: ~/.config/Thunar/uca.xml.broken, ~/.cache/Thunar, and ~/.local/share/Thunar. The idea was to force Thunar to start with a completely clean slate. When that didn't work, I tried more aggressive system process management – killing Thunar processes (thunar --quit, pkill thunar) and even restarting the XFCE session, just in case some background process was holding onto the bad state. I even tried forcing bash explicitly by prefixing commands with /usr/bin/env bash, hoping to override any potential sh fallback issues. Despite all these efforts – the reinstalls, downgrades, config clears, and process restarts – the core problems persisted. The erroneous ${base*} expansion was still showing up in generated wrappers, filenames were still getting mangled, and extensions were still disappearing. It was frustrating because none of the common troubleshooting steps seemed to fully resolve the underlying corruption that Thunar's UCA system was exhibiting.
Unmasking the Culprits: The Real Reasons for Failure
After a lot of trial and error, I pinpointed the main reasons why my Thunar custom actions were acting up. It wasn't just one single thing, but a combination of issues that created this perfect storm of broken functionality:
- Stale Wrapper Scripts Execution: This was a big one, guys. Even after I'd replaced the
uca.xmlfile with a clean, correct version, Thunar seemed to be executing old, corrupted wrapper scripts in the background. It was like it had a memory of the bad code and couldn't let go, even when presented with new instructions. This meant my fixes weren't being applied because Thunar was running the old broken code. - znver4 Build Specifics: As I suspected, the
znver4-optimized builds of Thunar were behaving differently. The way these builds handled UCA wrapper generation, argument expansion, and potential shell fallbacks was distinct from generic builds. This inconsistency made the problem harder to diagnose and fix, as solutions on a standard system might not apply directly. - Trailing Whitespace in
%fExpansion: Thunar was adding unexpected trailing whitespace to the%fargument when passing filenames to custom actions. This might seem minor, but it was enough to break filename parsing and extension detection within the scripts, leading to corrupt filenames and missing extensions. - Malformed Quoting and Shell Fallback: Issues with how Thunar quoted or escaped commands within the
<command>tags inuca.xmlsometimes caused the shell to fall back frombash(which I intended) to/bin/sh. Since/bin/shdoesn't always support the same features asbash, this fallback would break scripts that relied onbash-specific features.
Understanding these root causes was key to finding a real solution, not just a workaround.
The "Aha!" Moment: A Bulletproof Solution
So, after wrestling with Thunar's internal wrapper system and finding it unreliable, I decided to take a different approach. Instead of trying to fight with Thunar's buggy UCA generator, I opted to bypass it entirely. The real breakthrough came when I moved all the complex shell logic out of Thunar’s XML configuration and into a separate, standalone script. This way, Thunar just acts as a launcher, and the heavy lifting is done by a script that I have full control over. I also downgraded Thunar back to version 4.20.5, which seemed to have a more stable UCA implementation.
Here’s the strategy:
- Create an External Script: I created a new script, let's call it
/usr/local/bin/thunar-duplicate(you can name it whatever makes sense for its function). This script handles all the file manipulation logic. - Make Thunar Call the Script: In Thunar's UCA configuration (
uca.xml), the entry now simply points to this external script, passing the selected files using the%Fargument (which handles multiple files correctly). So, the UCA entry looks like this:/usr/local/bin/thunar-duplicate %F
This external script is designed to be robust and handles the issues Thunar was struggling with:
- Cleans Input: It first cleans up any potential trailing whitespace from the filenames passed by Thunar.
- Correct Filename/Extension Splitting: It reliably separates filenames from their extensions, even for files with multiple dots (like
archive.tar.gz). - Handles Multi-Dot Extensions: Explicitly coded to manage filenames like
my.document.v1.txtcorrectly. - Bypasses Thunar's Wrapper: By not relying on Thunar's internal wrapper generation, it avoids the
bad substitutionerrors, shell fallback issues, and inconsistent argument handling.
This approach completely resolved all the problems I was facing:
- No more
bad substitutionerrors. - Extensions are correctly preserved.
- Actions no longer fail silently.
- The wrapper corruption is gone.
- The inconsistencies seen with
znver4builds are eliminated because the script runs independently.
It’s a much cleaner and more reliable way to manage custom actions, especially for anything beyond the simplest tasks.
The Working External Script Example (/usr/local/bin/thunar-duplicate):
Here’s the bash script I created. It takes multiple files ($@), cleans them, determines a unique name (e.g., file_1.txt, file_2.txt), and then copies the original file to that new name. The sleep and thunar --select part is a nice touch to automatically select the newly created file in Thunar.
#!/usr/bin/env bash
# This script handles creating duplicate files with incrementing numbers.
# It's designed to bypass Thunar's problematic UCA wrapper.
# Loop through all files passed as arguments
for f in "$@"; do
# Clean up potential trailing whitespace from the filename
f_clean="$(printf "%s" "$f" | sed 's/[[:space:]]*$//')"
# Extract directory and base filename
dir="$(dirname -- "$f_clean")"
base="$(basename -- "$f_clean")"
# Separate filename from extension, handling multiple dots correctly
if [[ "$base" == *.* ]]; then
name="${base%.*}" # Filename part (e.g., "archive.tar")
ext=".${base##*.} " # Extension part (e.g., ".gz")
else
name="$base"
ext=""
fi
# Initialize duplicate counter
n=1
candidate="${name}_${n}${ext}"
# Find the next available number for the duplicate file
while [[ -e "$dir/$candidate" ]]; do
n=$((n+1))
candidate="${name}_${n}${ext}"
done
# Copy the original file to the new duplicate name
cp -a -- "$f_clean" "$dir/$candidate"
# *** Crucial Fix: Delayed selection ***
# After a short delay, select the newly created file in Thunar.
# This ensures Thunar has finished processing and doesn't interfere.
( sleep 0.2 && thunar --select "$dir/$candidate" ) & # Run in background
done
This external script approach is way more reliable and gives you the power to do complex things without worrying about Thunar's internal quirks.
What We Should Be Seeing: Expected Behavior
Honestly, when we set up custom actions, we expect them to just work. There shouldn't be this level of complexity just to get basic file operations going. Ideally, Thunar should behave predictably. Here’s what I believe is the expected, correct behavior for Thunar’s User Custom Actions:
- No Invalid Wrapper Code: Thunar should never generate invalid shell expansions like
${base*}. The wrapper code it creates internally must be syntactically correct shell script. - Clean
%fExpansion: The%fand%Farguments passed to custom actions should be clean. They absolutely should not contain unexpected trailing whitespace or other garbage that could break filename parsing. - Consistent Shell Usage: If a custom action specifies
bash -c '...', it should reliably execute usingbash. There should be no silent fallbacks to/bin/shthat break scripts relying onbash-specific features. The declared shell should be the one used. - Effective Cache Invalidation: When configuration files like
uca.xmlare updated, or when Thunar is reinstalled or upgraded, any corrupted UCA caches or stale wrapper scripts should be properly cleared. A clean install or config update should result in a completely clean state. - Predictable Behavior Across Builds: Optimized builds (like
znver4) and generic builds should handle core functionalities like UCA execution identically. Inconsistencies in these fundamental areas can lead to widespread issues and make system maintenance a nightmare. - Robustness for Complex Actions: While simple actions might work fine, Thunar should not actively prevent complex actions from working. If a user needs to do more involved scripting, Thunar's UCA system should support it without introducing errors or strange behavior.
Basically, we want our file manager to be a reliable tool, and its customization features should enhance our workflow, not create new problems.
A Message to the Maintainers: Let's Get This Fixed!
To the maintainers of Thunar and related packages, I really hope you'll take a look at this issue. Based on my experience, here are a few key areas that need investigation:
- Deep Dive into znver4 UCA Wrappers: Please investigate the specific behavior of Thunar's UCA wrapper generation on
znver4-optimized builds. Pay close attention to:- Invalid Variable Expansions: Why is
${base*}being generated? This is a critical bug. - Quoting and Escaping: Are there issues with how commands and arguments are quoted, leading to unexpected shell fallbacks?
- Shell Fallback Behavior: Analyze why
/bin/shmight be used instead ofbashwhenbashis explicitly requested.
- Invalid Variable Expansions: Why is
- Improve UCA Cache Management: The current behavior where stale or broken UCA wrappers persist even after configuration changes is problematic. Enhancing UCA cache invalidation logic would prevent many such issues.
- Verify Argument Expansion (
%f,%F): Ensure that arguments like%fand%Fare always expanded correctly, without any leading/trailing whitespace or corruption, regardless of the filename or build type. - Ensure Consistent
bash -cExecution: Confirm that when<command>tags explicitly requestbash -c, Thunar reliably invokesbashand doesn't fall back tosh, especially when dealing with complex commands or specific build environments. - Consider Recommending External Scripts: For complex custom actions, Thunar’s internal wrapper system seems to be a weak point. Perhaps Thunar's documentation could recommend or even encourage the use of external scripts for advanced UCAs to avoid these wrapper-related issues altogether.
- Rollback Recommendation: Until these UCA issues are resolved, consider maintaining the stable version (Thunar 4.20.5) on your repositories, or at least provide clear guidance on how users can downgrade safely if they encounter these problems. It would save a lot of users a significant amount of troubleshooting time.
I believe addressing these points will not only fix the immediate problem for users like me but also make Thunar's custom actions feature much more robust and reliable for everyone. Thanks for your hard work on this fantastic file manager!