What Is the `side_effect` Function in a thefuck Rule?
The side_effect function in a thefuck rule performs cleanup or preparatory actions—such as deleting corrupted files or removing invalid SSH host keys—after a user accepts a suggested fix but before the corrected command actually executes.
The side_effect function is an optional component in rules for nvbn/thefuck, the popular command-line tool that corrects mistyped console commands. When a rule matches a failed command and generates a fix, this function handles necessary filesystem or environment modifications that fall outside the scope of the command syntax itself, ensuring the retry succeeds in a cleaned environment.
Purpose of the side_effect Function in thefuck Rules
In the thefuck architecture, each rule can define three core functions: match(command), get_new_command(command), and optionally side_effect(old_cmd, command). While match determines if the rule applies and get_new_command generates the replacement syntax, side_effect executes after the user confirms the suggestion but before the new command runs.
This timing is critical for scenarios where the corrected command would fail if executed immediately against the current system state. The function serves as a bridge between error detection and successful retry execution, performing operations that must happen outside the command itself.
Common Use Cases for side_effect
| Scenario | What side_effect Does |
Example Rule |
|---|---|---|
| SSH host key mismatch | Parses error output, opens ~/.ssh/known_hosts, deletes the offending line by line number, writes the file back. |
thefuck/rules/ssh_known_hosts.py |
| Partial unzip cleanup | Opens the zip archive, identifies extracted files in the current directory, removes them to prevent "file already exists" errors on retry. | thefuck/rules/dirty_unzip.py |
| Tar extraction residue | Uses tarfile.TarFile to list members and deletes each extracted file before retrying with proper -C options. |
thefuck/rules/dirty_untar.py |
In all three cases, the corrected command (get_new_command) would fail again if leftover artifacts remained in place. By cleaning the environment first, the rule guarantees that the user's next attempt succeeds.
How the thefuck Engine Executes side_effect
The execution flow in thefuck/rules/__init__.py and the main engine follows a strict sequence when processing a failed command:
- Match Detection: The engine calls
match(command)on each rule until one returnsTrue. - Fix Generation: The matching rule's
get_new_command(command)produces the replacement command string. - User Confirmation: The engine displays the suggestion and waits for user acceptance.
- Side Effect Execution: If the rule defines
side_effect, the engine callsside_effect(old_cmd, command)with the originalCommandobject and the newCommandobject. - Command Execution: The cleaned-up environment now runs the new command.
The signature side_effect(old_cmd, command) gives the function access to:
old_cmd.output,old_cmd.script, etc. — the original failing command's output for parsing.command.script— the corrected command (often not needed, but available).
Because the function can modify files, remove directories, or perform any other OS-side operation, it must be idempotent and safe (the rules usually check that affected paths stay inside the current working directory).
Real-World Implementation Examples
Cleaning SSH Known Hosts in ssh_known_hosts.py
The ssh_known_hosts rule handles host key mismatch errors by parsing the SSH error output to identify the offending line number in ~/.ssh/known_hosts, then removing that specific line before the retry.
def side_effect(old_cmd, command):
offending_pattern = re.compile(
r'(?:Offending (?:key for IP|\S+ key)|Matching host key) in ([^:]+):(\d+)',
re.MULTILINE)
offending = offending_pattern.findall(old_cmd.output)
for filepath, lineno in offending:
with open(filepath, 'r') as fh:
lines = fh.readlines()
del lines[int(lineno) - 1] # remove the bad key line
with open(filepath, 'w') as fh:
fh.writelines(lines) # write the cleaned file back
Source: [thefuck/rules/ssh_known_hosts.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/ssh_known_hosts.py#L27-L38)
Removing Partial Unzip Artifacts in dirty_unzip.py
When unzip fails partway through extraction (leaving incomplete files), the dirty_unzip rule cleans up these artifacts before retrying with proper flags.
def side_effect(old_cmd, command):
# Extracted files are removed, zip file is kept
with zipfile.ZipFile('sample.zip', 'r') as archive:
for file in archive.namelist():
try:
os.remove(file)
except OSError:
pass
Source: [thefuck/rules/dirty_unzip.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/dirty_unzip.py#L45-L58)
Cleaning Tar Extraction Residue in dirty_untar.py
Similar to the unzip scenario, the dirty_untar rule removes partially extracted files from failed tar commands before retrying with the correct directory or extraction options.
def side_effect(old_cmd, command):
# Remove extracted files before retrying
import tarfile
with tarfile.TarFile('archive.tar', 'r') as tar:
for member in tar.getmembers():
if member.isfile():
try:
os.remove(member.name)
except OSError:
pass
Source: [thefuck/rules/dirty_untar.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/dirty_untar.py#L41-L53)
Creating a Custom Rule with side_effect
To create a rule with cleanup logic, define side_effect(old_cmd, command) alongside match and get_new_command. The function should parse old_cmd.output to identify what needs cleaning, perform the operation, and handle errors gracefully.
# thefuck/rules/example_cleanup.py
from thefuck.utils import for_app
@for_app('mycmd')
def match(command):
return 'ERROR: already exists' in command.output
def get_new_command(command):
# retry with a force flag
return f'{command.script} --force'
def side_effect(old_cmd, command):
# Delete the file that caused the "already exists" error
import os, re
m = re.search(r'File: (.+) already exists', old_cmd.output)
if m:
filepath = m.group(1)
if os.path.isfile(filepath):
os.remove(filepath)
When the user runs $ mycmd project and sees ERROR: project already exists (File: ./project), thefuck proposes mycmd project --force. If the user accepts, side_effect removes ./project before executing the forced command, ensuring the retry succeeds.
Key Files in the thefuck Repository
| File | Role | Link |
|---|---|---|
thefuck/utils.py |
Defines for_app decorator and helper utilities used by rules. |
[utils.py](https://github.com/nvbn/thefuck/blob/master/thefuck/utils.py) |
thefuck/rules/ssh_known_hosts.py |
Demonstrates side-effect that edits known_hosts. |
[ssh_known_hosts.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/ssh_known_hosts.py) |
thefuck/rules/dirty_unzip.py |
Side-effect that removes unsafe extracted files before re-unzip. | [dirty_unzip.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/dirty_unzip.py) |
thefuck/rules/dirty_untar.py |
Side-effect that cleans up partially extracted tar files. | [dirty_untar.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/dirty_untar.py) |
thefuck/rules/__init__.py |
Registers all rule modules, enabling the engine to discover optional side_effect functions. |
[__init__.py](https://github.com/nvbn/thefuck/blob/master/thefuck/rules/__init__.py) |
These files together illustrate how thefuck leverages the optional side_effect function to keep the filesystem in a consistent state, allowing the corrected command to succeed on the very next run.
Summary
- The
side_effectfunction in nvbn/thefuck rules performs cleanup or preparation after a user accepts a fix but before the corrected command executes. - It receives two parameters:
old_cmd(the original failed command with output) andcommand(the new command), allowing it to parse error details and modify the environment. - Common use cases include removing invalid SSH host keys from
~/.ssh/known_hosts, cleaning up partial archive extractions from failedunziportarcommands, and deleting lock files that prevent command retries. - Real-world implementations in
thefuck/rules/ssh_known_hosts.py,thefuck/rules/dirty_unzip.py, andthefuck/rules/dirty_untar.pydemonstrate parsing regex patterns fromold_cmd.outputto identify and remove specific files or lines. - When implementing custom rules,
side_effectshould be idempotent, validate paths stay within safe directories, and handle OS errors gracefully to avoid disrupting the user's system.
Frequently Asked Questions
When is the side_effect function called in the thefuck execution flow?
The side_effect function executes after the user confirms a suggested fix but before the corrected command runs. Specifically, the thefuck engine calls match(command) to identify the rule, get_new_command(command) to generate the fix, prompts the user for confirmation, and then invokes side_effect(old_cmd, command) to perform cleanup before finally executing the corrected command.
What parameters does the side_effect function receive?
The function receives two parameters: old_cmd and command. The old_cmd object represents the original failed command and contains attributes like old_cmd.output (the stderr/stdout for parsing error details) and old_cmd.script (the original command string). The command object represents the new corrected command, with command.script containing the proposed fix.
Can a thefuck rule work without a side_effect function?
Yes, the side_effect function is entirely optional. Most rules in thefuck only implement match and get_new_command. The engine checks for the existence of side_effect using introspection, calling it only if defined. Rules that suggest different command syntax without modifying the filesystem or environment do not require this function.
How do I ensure my side_effect function is safe?
To write a safe side_effect function, validate that any file paths you modify stay within the current working directory or other safe zones, use try-except blocks to handle OSError exceptions when deleting files, and ensure the operation is idempotent (running it multiple times should not cause errors). Study the reference implementations in thefuck/rules/dirty_unzip.py and thefuck/rules/ssh_known_hosts.py for patterns on parsing output safely and handling filesystem operations defensively.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →