* naive implementation * better implementation * remove redundant enabled_by_default Co-authored-by: Pablo Aguiar <scorphus@gmail.com> * add README entry * add tests Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
The Fuck  
  
  
  
 
The Fuck is a magnificent app, inspired by a @liamosaur tweet, that corrects errors in previous console commands.
Is The Fuck too slow? Try the experimental instant mode!
More examples:
➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?
➜ fuck
sudo apt-get install vim [enter/↑/↓/ctrl+c]
[sudo] password for nvbn:
Reading package lists... Done
...
➜ git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use
    git push --set-upstream origin master
➜ fuck
git push --set-upstream origin master [enter/↑/↓/ctrl+c]
Counting objects: 9, done.
...
➜ puthon
No command 'puthon' found, did you mean:
 Command 'python' from package 'python-minimal' (main)
 Command 'python' from package 'python3' (main)
zsh: command not found: puthon
➜ fuck
python [enter/↑/↓/ctrl+c]
Python 3.4.2 (default, Oct  8 2014, 13:08:17)
...
➜ git brnch
git: 'brnch' is not a git command. See 'git --help'.
Did you mean this?
    branch
➜ fuck
git branch [enter/↑/↓/ctrl+c]
* master
➜ lein rpl
'rpl' is not a task. See 'lein help'.
Did you mean this?
         repl
➜ fuck
lein repl [enter/↑/↓/ctrl+c]
nREPL server started on port 54848 on host 127.0.0.1 - nrepl://127.0.0.1:54848
REPL-y 0.3.1
...
If you're not afraid of blindly running corrected commands, the
require_confirmation settings option can be disabled:
➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?
➜ fuck
sudo apt-get install vim
[sudo] password for nvbn:
Reading package lists... Done
...
Requirements
- python (3.4+)
- pip
- python-dev
Installation
On OS X, you can install The Fuck via Homebrew (or via Linuxbrew on Linux):
brew install thefuck
On Ubuntu / Mint, install The Fuck with the following commands:
sudo apt update
sudo apt install python3-dev python3-pip python3-setuptools
sudo pip3 install thefuck
On FreeBSD, install The Fuck with the following commands:
pkg install thefuck
On ChromeOS, install The Fuck using chromebrew with the following command:
crew install thefuck
On other systems, install The Fuck  by using pip:
pip install thefuck
Alternatively, you may use an OS package manager (OS X, Ubuntu, Arch).
#
It is recommended that you place this command in your .bash_profile,
.bashrc, .zshrc or other startup script:
eval $(thefuck --alias)
# You can use whatever you want as an alias, like for Mondays:
eval $(thefuck --alias FUCK)
Or in your shell config (Bash, Zsh, Fish, Powershell, tcsh).
Changes are only available in a new shell session. To make changes immediately
available, run source ~/.bashrc (or your shell config file like .zshrc).
To run fixed commands without confirmation, use the --yeah option (or just -y for short, or --hard if you're especially frustrated):
fuck --yeah
To fix commands recursively until succeeding, use the -r option:
fuck -r
Updating
pip3 install thefuck --upgrade
Note: Alias functionality was changed in v1.34 of The Fuck
How it works
The Fuck attempts to match the previous command with a rule. If a match is found, a new command is created using the matched rule and executed. The following rules are enabled by default:
- adb_unknown_command– fixes misspelled commands like- adb logcta;
- ag_literal– adds- -Qto- agwhen suggested;
- aws_cli– fixes misspelled commands like- aws dynamdb scan;
- az_cli– fixes misspelled commands like- az providers;
- cargo– runs- cargo buildinstead of- cargo;
- cargo_no_command– fixes wrongs commands like- cargo buid;
- cat_dir– replaces- catwith- lswhen you try to- cata directory;
- cd_correction– spellchecks and correct failed cd commands;
- cd_mkdir– creates directories before cd'ing into them;
- cd_parent– changes- cd..to- cd ..;
- chmod_x– add execution bit;
- choco_install– append common suffixes for chocolatey packages;
- composer_not_command– fixes composer command name;
- cp_create_destination– creates a new directory when you attempt to- cpor- mvto a non existent one
- cp_omitting_directory– adds- -awhen you- cpdirectory;
- cpp11– adds missing- -std=c++11to- g++or- clang++;
- dirty_untar– fixes- tar xcommand that untarred in the current directory;
- dirty_unzip– fixes- unzipcommand that unzipped in the current directory;
- django_south_ghost– adds- --delete-ghost-migrationsto failed because ghosts django south migration;
- django_south_merge– adds- --mergeto inconsistent django south migration;
- docker_login– executes a- docker loginand repeats the previous command;
- docker_not_command– fixes wrong docker commands like- docker tags;
- docker_image_being_used_by_container‐ removes the container that is using the image before removing the image;
- dry– fixes repetitions like- git git push;
- fab_command_not_found– fix misspelled fabric commands;
- fix_alt_space– replaces Alt+Space with Space character;
- fix_file– opens a file with an error in your- $EDITOR;
- gem_unknown_command– fixes wrong- gemcommands;
- git_add– fixes "pathspec 'foo' did not match any file(s) known to git.";
- git_add_force– adds- --forceto- git add <pathspec>...when paths are .gitignore'd;
- git_bisect_usage– fixes- git bisect strt,- git bisect goood,- git bisect rset, etc. when bisecting;
- git_branch_delete– changes- git branch -dto- git branch -D;
- git_branch_delete_checked_out– changes- git branch -dto- git checkout master && git branch -Dwhen trying to delete a checked out branch;
- git_branch_exists– offers- git branch -d foo,- git branch -D fooor- git checkout foowhen creating a branch that already exists;
- git_branch_list– catches- git branch listin place of- git branchand removes created branch;
- git_checkout– fixes branch name or creates new branch;
- git_commit_amend– offers- git commit --amendafter previous commit;
- git_commit_reset– offers- git reset HEAD~after previous commit;
- git_diff_no_index– adds- --no-indexto previous- git diffon untracked files;
- git_diff_staged– adds- --stagedto previous- git diffwith unexpected output;
- git_fix_stash– fixes- git stashcommands (misspelled subcommand and missing- save);
- git_flag_after_filename– fixes- fatal: bad flag '...' after filename
- git_help_aliased– fixes- git help <alias>commands replacing with the aliased command;
- git_hook_bypass– adds- --no-verifyflag previous to- git am,- git commit, or- git pushcommand;
- git_lfs_mistype– fixes mistyped- git lfs <command>commands;
- git_merge– adds remote to branch names;
- git_merge_unrelated– adds- --allow-unrelated-historieswhen required
- git_not_command– fixes wrong git commands like- git brnch;
- git_pull– sets upstream before executing previous- git pull;
- git_pull_clone– clones instead of pulling when the repo does not exist;
- git_pull_uncommitted_changes– stashes changes before pulling and pops them afterwards;
- git_push– adds- --set-upstream origin $branchto previous failed- git push;
- git_push_different_branch_names– fixes pushes when local brach name does not match remote branch name;
- git_push_pull– runs- git pullwhen- pushwas rejected;
- git_push_without_commits– Creates an initial commit if you forget and only- git add ., when setting up a new project;
- git_rebase_no_changes– runs- git rebase --skipinstead of- git rebase --continuewhen there are no changes;
- git_remote_delete– replaces- git remote delete remote_namewith- git remote remove remote_name;
- git_rm_local_modifications– adds- -for- --cachedwhen you try to- rma locally modified file;
- git_rm_recursive– adds- -rwhen you try to- rma directory;
- git_rm_staged– adds- -for- --cachedwhen you try to- rma file with staged changes
- git_rebase_merge_dir– offers- git rebase (--continue | --abort | --skip)or removing the- .git/rebase-mergedir when a rebase is in progress;
- git_remote_seturl_add– runs- git remote addwhen- git remote set_urlon nonexistent remote;
- git_stash– stashes your local modifications before rebasing or switching branch;
- git_stash_pop– adds your local modifications before popping stash, then resets;
- git_tag_force– adds- --forceto- git tag <tagname>when the tag already exists;
- git_two_dashes– adds a missing dash to commands like- git commit -amendor- git rebase -continue;
- go_run– appends- .goextension when compiling/running Go programs;
- go_unknown_command– fixes wrong- gocommands, for example- go bulid;
- gradle_no_task– fixes not found or ambiguous- gradletask;
- gradle_wrapper– replaces- gradlewith- ./gradlew;
- grep_arguments_order– fixes- greparguments order for situations like- grep -lir . test;
- grep_recursive– adds- -rwhen you try to- grepdirectory;
- grunt_task_not_found– fixes misspelled- gruntcommands;
- gulp_not_task– fixes misspelled- gulptasks;
- has_exists_script– prepends- ./when script/binary exists;
- heroku_multiple_apps– add- --app <app>to- herokucommands like- heroku pg;
- heroku_not_command– fixes wrong- herokucommands like- heroku log;
- history– tries to replace command with most similar command from history;
- hostscli– tries to fix- hostscliusage;
- ifconfig_device_not_found– fixes wrong device names like- wlan0to- wlp2s0;
- java– removes- .javaextension when running Java programs;
- javac– appends missing- .javawhen compiling Java files;
- lein_not_task– fixes wrong- leintasks like- lein rpl;
- long_form_help– changes- -hto- --helpwhen the short form version is not supported
- ln_no_hard_link– catches hard link creation on directories, suggest symbolic link;
- ln_s_order– fixes- ln -sarguments order;
- ls_all– adds- -Ato- lswhen output is empty;
- ls_lah– adds- -lahto- ls;
- man– changes manual section;
- man_no_space– fixes man commands without spaces, for example- mandiff;
- mercurial– fixes wrong- hgcommands;
- missing_space_before_subcommand– fixes command with missing space like- npminstall;
- mkdir_p– adds- -pwhen you try to create a directory without parent;
- mvn_no_command– adds- clean packageto- mvn;
- mvn_unknown_lifecycle_phase– fixes misspelled life cycle phases with- mvn;
- npm_missing_script– fixes- npmcustom script name in- npm run-script <script>;
- npm_run_script– adds missing- run-scriptfor custom- npmscripts;
- npm_wrong_command– fixes wrong npm commands like- npm urgrade;
- no_command– fixes wrong console commands, for example- vom/vim;
- no_such_file– creates missing directories with- mvand- cpcommands;
- open– either prepends- http://to address passed to- openor create a new file or directory and passes it to- open;
- pip_install– fixes permission issues with- pip installcommands by adding- --useror prepending- sudoif necessary;
- pip_unknown_command– fixes wrong- pipcommands, for example- pip instatl/pip install;
- php_s– replaces- -sby- -Swhen trying to run a local php server;
- port_already_in_use– kills process that bound port;
- prove_recursively– adds- -rwhen called with directory;
- pyenv_no_such_command– fixes wrong pyenv commands like- pyenv isntallor- pyenv list;
- python_command– prepends- pythonwhen you try to run non-executable/without- ./python script;
- python_execute– appends missing- .pywhen executing Python files;
- quotation_marks– fixes uneven usage of- 'and- "when containing args';
- path_from_history– replaces not found path with similar absolute path from history;
- react_native_command_unrecognized– fixes unrecognized- react-nativecommands;
- remove_shell_prompt_literal– remove leading shell prompt symbol- $, common when copying commands from documentations;
- remove_trailing_cedilla– remove trailing cedillas- ç, a common typo for european keyboard layouts;
- rm_dir– adds- -rfwhen you try to remove a directory;
- scm_correction– corrects wrong scm like- hg logto- git log;
- sed_unterminated_s– adds missing '/' to- sed's- scommands;
- sl_ls– changes- slto- ls;
- ssh_known_hosts– removes host from- known_hostson warning;
- sudo– prepends- sudoto previous command if it failed because of permissions;
- sudo_command_from_user_path– runs commands from users- $PATHwith- sudo;
- switch_lang– switches command from your local layout to en;
- systemctl– correctly orders parameters of confusing- systemctl;
- terraform_init.py– run- terraform initbefore plan or apply;
- test.py– runs- py.testinstead of- test.py;
- touch– creates missing directories before "touching";
- tsuru_login– runs- tsuru loginif not authenticated or session expired;
- tsuru_not_command– fixes wrong- tsurucommands like- tsuru shell;
- tmux– fixes- tmuxcommands;
- unknown_command– fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on- hdfs dfs ls;
- unsudo– removes- sudofrom previous command if a process refuses to run on super user privilege.
- vagrant_up– starts up the vagrant instance;
- whois– fixes- whoiscommand;
- workon_doesnt_exists– fixes- virtualenvwrapperenv name os suggests to create new.
- yarn_alias– fixes aliased- yarncommands like- yarn ls;
- yarn_command_not_found– fixes misspelled- yarncommands;
- yarn_command_replaced– fixes replaced- yarncommands;
- yarn_help– makes it easier to open- yarndocumentation;
The following rules are enabled by default on specific platforms only:
- apt_get– installs app from apt if it not installed (requires- python-commandnotfound/- python3-commandnotfound);
- apt_get_search– changes trying to search using- apt-getwith searching using- apt-cache;
- apt_invalid_operation– fixes invalid- aptand- apt-getcalls, like- apt-get isntall vim;
- apt_list_upgradable– helps you run- apt list --upgradableafter- apt update;
- apt_upgrade– helps you run- apt upgradeafter- apt list --upgradable;
- brew_cask_dependency– installs cask dependencies;
- brew_install– fixes formula name for- brew install;
- brew_reinstall– turns- brew install <formula>into- brew reinstall <formula>;
- brew_link– adds- --overwrite --dry-runif linking fails;
- brew_uninstall– adds- --forceto- brew uninstallif multiple versions were installed;
- brew_unknown_command– fixes wrong brew commands, for example- brew docto/brew doctor;
- brew_update_formula– turns- brew update <formula>into- brew upgrade <formula>;
- dnf_no_such_command– fixes mistyped DNF commands;
- nixos_cmd_not_found– installs apps on NixOS;
- pacman– installs app with- pacmanif it is not installed (uses- yayor- yaourtif available);
- pacman_invalid_option– replaces lowercase- pacmanoptions with uppercase.
- pacman_not_found– fixes package name with- pacman,- yayor- yaourt.
- yum_invalid_operation– fixes invalid- yumcalls, like- yum isntall vim;
The following commands are bundled with The Fuck, but are not enabled by default:
- git_push_force– adds- --force-with-leaseto a- git push(may conflict with- git_push_pull);
- rm_root– adds- --no-preserve-rootto- rm -rf /command.
Creating your own rules
To add your own rule, create a file named your-rule-name.py
in ~/.config/thefuck/rules. The rule file must contain two functions:
match(command: Command) -> bool
get_new_command(command: Command) -> str | list[str]
Additionally, rules can contain optional functions:
side_effect(old_command: Command, fixed_command: str) -> None
Rules can also contain the optional variables enabled_by_default, requires_output and priority.
Command has three attributes: script, output and script_parts.
Your rule should not change Command.
Rules api changed in 3.0: To access a rule's settings, import it with
from thefuck.conf import settings
settings is a special object assembled from ~/.config/thefuck/settings.py,
and values from env (see more below).
A simple example rule for running a script with sudo:
def match(command):
    return ('permission denied' in command.output.lower()
            or 'EACCES' in command.output)
def get_new_command(command):
    return 'sudo {}'.format(command.script)
# Optional:
enabled_by_default = True
def side_effect(command, fixed_command):
    subprocess.call('chmod 777 .', shell=True)
priority = 1000  # Lower first, default is 1000
requires_output = True
More examples of rules, utility functions for rules, app/os-specific helpers.
Settings
Several The Fuck parameters can be changed in the file $XDG_CONFIG_HOME/thefuck/settings.py
($XDG_CONFIG_HOME defaults to ~/.config):
- rules– list of enabled rules, by default- thefuck.const.DEFAULT_RULES;
- exclude_rules– list of disabled rules, by default- [];
- require_confirmation– requires confirmation before running new command, by default- True;
- wait_command– max amount of time in seconds for getting previous command output;
- no_colors– disable colored output;
- priority– dict with rules priorities, rule with lower- prioritywill be matched first;
- debug– enables debug output, by default- False;
- history_limit– numeric value of how many history commands will be scanned, like- 2000;
- alter_history– push fixed command to history, by default- True;
- wait_slow_command– max amount of time in seconds for getting previous command output if it in- slow_commandslist;
- slow_commands– list of slow commands;
- num_close_matches– maximum number of close matches to suggest, by default- 3.
An example of settings.py:
rules = ['sudo', 'no_command']
exclude_rules = ['git_push']
require_confirmation = True
wait_command = 10
no_colors = False
priority = {'sudo': 100, 'no_command': 9999}
debug = False
history_limit = 9999
wait_slow_command = 20
slow_commands = ['react-native', 'gradle']
num_close_matches = 5
Or via environment variables:
- THEFUCK_RULES– list of enabled rules, like- DEFAULT_RULES:rm_rootor- sudo:no_command;
- THEFUCK_EXCLUDE_RULES– list of disabled rules, like- git_pull:git_push;
- THEFUCK_REQUIRE_CONFIRMATION– require confirmation before running new command,- true/false;
- THEFUCK_WAIT_COMMAND– max amount of time in seconds for getting previous command output;
- THEFUCK_NO_COLORS– disable colored output,- true/false;
- THEFUCK_PRIORITY– priority of the rules, like- no_command=9999:apt_get=100, rule with lower- prioritywill be matched first;
- THEFUCK_DEBUG– enables debug output,- true/false;
- THEFUCK_HISTORY_LIMIT– how many history commands will be scanned, like- 2000;
- THEFUCK_ALTER_HISTORY– push fixed command to history- true/false;
- THEFUCK_WAIT_SLOW_COMMAND– max amount of time in seconds for getting previous command output if it in- slow_commandslist;
- THEFUCK_SLOW_COMMANDS– list of slow commands, like- lein:gradle;
- THEFUCK_NUM_CLOSE_MATCHES– maximum number of close matches to suggest, like- 5.
For example:
export THEFUCK_RULES='sudo:no_command'
export THEFUCK_EXCLUDE_RULES='git_pull:git_push'
export THEFUCK_REQUIRE_CONFIRMATION='true'
export THEFUCK_WAIT_COMMAND=10
export THEFUCK_NO_COLORS='false'
export THEFUCK_PRIORITY='no_command=9999:apt_get=100'
export THEFUCK_HISTORY_LIMIT='2000'
export THEFUCK_NUM_CLOSE_MATCHES='5'
Third-party packages with rules
If you'd like to make a specific set of non-public rules, but would still like
to share them with others, create a package named thefuck_contrib_* with
the following structure:
thefuck_contrib_foo
  thefuck_contrib_foo
    rules
      __init__.py
      *third-party rules*
    __init__.py
    *third-party-utils*
  setup.py
The Fuck will find rules located in the rules module.
Experimental instant mode
The default behavior of The Fuck requires time to re-run previous commands. When in instant mode, The Fuck saves time by logging output with script, then reading the log.
Currently, instant mode only supports Python 3 with bash or zsh. zsh's autocorrect function also needs to be disabled in order for thefuck to work properly.
To enable instant mode, add --enable-experimental-instant-mode
to the alias initialization in .bashrc, .bash_profile or .zshrc.
For example:
eval $(thefuck --alias --enable-experimental-instant-mode)
Developing
See CONTRIBUTING.md
License MIT
Project License can be found here.

