Can You Prevent a Command from Going into the Bash Shell Command History

Can you prevent a command from going into the bash shell command history?

On newer Bash Versions you could simply add a space at the beginning of your command. :)
If it doesn't work by default, add [ \t]* to HISTIGNORE. (As mentioned in the comments. thx)

How do I prevent commands from showing up in Bash history?

If you've set the HISTCONTROL environment variable to ignoreboth (which is usually set by default), commands with a leading space character will not be stored in the history (as well as duplicates).

For example:

$ HISTCONTROL=ignoreboth
$ echo test1
$ echo test2
$ history | tail -n2
1015 echo test1
1016 history | tail -n2

Here is what man bash says:

HISTCONTROL

A colon-separated list of values controlling how commands are saved on the history list. If the list of values includes ignorespace, lines which begin with a space character are not saved in the history list. A value of ignoredups causes lines matching the previous history entry to not be saved. A value of ignoreboth is shorthand for ignorespace and ignoredups. A value of erasedups causes all previous lines matching the current line to be removed from the history list before that line is saved. Any value not in the above list is ignored. If HISTCONTROL is unset, or does not include a valid value, all lines read by the shell parser are saved on the history list, subject to the value of HISTIGNORE. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regardless of the value of HISTCONTROL.

See also:

  • Why is bash not storing commands that start with spaces? at unix SE
  • Why does bash have a HISTCONTROL=ignorespace option? at unix SE

Avoid adding bash command to history

Use the value ignorespace in the shell variable HISTCONTROL, e.g. by setting it in ~/.bashrc like this.

HISTCONTROL=ignorespace

Now you can prefix the command line with a space, and it will be ignored:

$  export SECRET=sensitive  # Intentional blank at the beginning of the line
$ echo $SECRET

From the Bash docs:

HISTCONTROL

A colon-separated list of values controlling how commands are
saved on the history list. If the list of values includes
ignorespace, lines which begin with a space character are not
saved in the history list. A value of ignoredups causes lines
matching the previous history entry to not be saved. A value of
ignoreboth is shorthand for ignorespace and ignoredups. A value
of erasedups causes all previous lines matching the current line
to be removed from the history list before that line is saved.
Any value not in the above list is ignored. If HISTCONTROL is
unset, or does not include a valid value, all lines read by the
shell parser are saved on the history list, subject to the value
of HISTIGNORE. The second and subsequent lines of a multi-line
compound command are not tested, and are added to the history
regardless of the value of HISTCONTROL.

Execute a command without keeping it in history

Start your command with a space and it won't be included in the history.

Be aware that this does require the environment variable $HISTCONTROL to be set.

  • Check that the following command returns ignorespace or
    ignoreboth:

     echo $HISTCONTROL
  • To add the environment variable if missing, the following line can be added to the Bash profile. E.g., to file %HOME/.bashrc.

     export HISTCONTROL=ignorespace

After sourcing the profile again, space-prefixed commands will not be written to $HISTFILE.

Sanitising command before storing it in bash history

I'm not sure how foolproof this is; it might miss some way of supplying the -f option. That said, you can override rm with the following:

rm () {
local HISTIGNORE="$HISTIGNORE:command rm *"
local arg process
local -a sanitized
command rm "$@"
process=true
for arg in "$@"; do
if [[ $process && $arg = -*f* ]]; then
sanitized+=("${arg//f/}")
elif [[ $arg == -- ]]; then
process=
else
sanitized+=("$arg")
fi
done
history -s rm "${sanitized[@]}"
}

This works as follows:

  1. Temporarily add the pattern command rm * to the HISTIGNORE list, so that the command about to be executed isn't added to history.
  2. Execute the command as requested.
  3. Walk through the arguments, looking for any that contain the -f option. (Either standalone or in a cluster of short options.) Any such word should have the f removed. Sanitized words are added to a new array.
  4. The history -s command adds the reconstructed command (with sanitized arguments) to the history list.

How to disable editing my history in bash

Here's my own answer, please correct or provide more details if you can.

When the "vi" option is set in bash ("set -o vi" -- "Use a vi-style command line editing interface"), there are two modes of editing a command from history.

The first mode (let's call it "basic") is when you start editing immediately using Backspace, Del and character keys.

The other mode is the "vi mode", entered when you hit Esc.

If you want to keep your history intact, DO NOT use both modes in the same edit. I don't know how bash works exactly, but you can think of it this way:

  1. Entering the "vi mode" applies any changes done in "basic mode" to the original command, and creates a copy of the command that you can edit further using vi-style commands.
  2. The changes get applied when you hit Enter (execute), Up, Down or j,k (move to another command in history).
  3. The changes do not get applied if you hit Ctrl-C.
  4. Using either basic or vi-style editing ALONE does not affect the original command in history.

When using the terminal history, can I force confirmation when executing dangerous commands from my history?

Use Functions as Command Wrappers

The shell doesn't directly support this feature, in part because a command is stored in history before it is executed. However, you can largely fake it by wrapping your "dangerous" commands in functions that take precedence over the real commands. For example:

rm () {
local regex='[Yy]'
if history | sed '$d' | pcregrep -q "^\s+\d+\s+${FUNCNAME} $*"; then
read -p 'Are you sure? '
[[ "$REPLY" =~ $regex ]] || return 1
fi
command "$FUNCNAME" "$@"
}

The secret sauce is the sed command that strips out the current command that's just been stored in history. Without that, grep would always find the command in the history.

Caveats

  1. Note the requirement for a grep compiled with PCRE support. You will need to adjust the regular expression if you don't have pcregrep or egrep compiled with PCRE support.
  2. You might also have to adjust quoting or use eval if word splitting doesn't happen the way you think it should, but it worked fine for me in casual testing. Your mileage may vary.


Related Topics



Leave a reply



Submit