"위험한" 명령이 bash 기록에 기록되는 것을 방지하기 위해 파일에 다음 줄을 추가했습니다 .bashrc
.
HISTIGNORE='rm *:mv *:cp *:cat*>*:pv*>*'
이것은 훌륭하게 작동하지만 부작용이 있습니다. 컴퓨터에서 실행된 명령의 전체 기록을 볼 수 없습니다. 실험용 컴퓨터가 몇 대 있고 실행되는 모든 명령을 볼 수 있기를 원한다고 가정해 보겠습니다. bash 내부를 사용하여 history
실행된 명령을 표시하고 grep을 사용하여 오늘 날짜를 표시할 수도 있습니다.
history | grep Sep-28
내가 하고 싶은 것은 "위험한" 명령도 기록하되, #
실수로 기록에서 명령을 실행하더라도 손상이 발생하지 않도록 줄 시작 부분에 하나를 넣는 것입니다.
이것이 가능한지 모르겠습니다.
업데이트 및 설명:
이것이 나에게 문제가 되는 주된 이유는 일반적으로 여러 터미널에서 내 컴퓨터에 연결하고 한 터미널에서 실행된 모든 명령이 즉시 다른 터미널의 기록으로 읽혀지기 때문입니다. 이는 다음에 의해 달성됩니다.
PROMPT_COMMAND="history -a; history -c; history -r"
두 개의 터미널이 열려 있다고 가정 해 보겠습니다. 그 중 하나에서 cat /dev/foo > file.out
몇 가지 프로세스를 실행하고 있습니다. 두 번째 단계에서는 check 진행률을 사용합니다 ls -lAhF
. and (즉, 기록의 마지막 명령)를 ls
눌러 계속 반복 합니다 . 첫 번째 명령이 완료되면 더 이상 기록의 마지막 명령이 아닙니다 . 조심하지 않으면 cat을 다시 시작하고 file.out을 덮어씁니다.UpENTERls
cat /dev/foo > file.out
#
내가 달성하고 싶은 것은 실행되지 않도록 cat 명령 앞에 a를 두는 것입니다 . 그러나 기록에서는 계속 볼 수 있으며 주석을 제거하여 재사용할 수 있습니다(긴 명령인 경우).
답변1
귀하의 질문에 정확하게 답변하지는 않지만 귀하의 문제에 대한 대체 솔루션을 제공할 수도 있습니다.
내가 올바르게 이해했다면, 입력하는 동안 발생할 수 있는 실수에 대해 걱정하고 계시는 것입니다. 예를 들어 기록의 이전 명령이 유지하고 싶은 항목을 삭제한 !rm
경우입니다 .rm
이 경우에는 좋은세게 때리다옵션은 입니다 histverify
. shopt -s histverify
bang 으로 명령을 호출 하면 !
즉시 실행되지 않고 readline에 로드되어 실행 여부를 결정할 수 있으며 편집도 가능합니다.
시도 해봐:
아니요
histverify
:$ touch some_foo $ rm some_foo $ touch some_foo $ !rm rm some_foo $ # oooops in fact I'd've like to keep it this time
그리고
histverify
:$ shopt -s histverify $ touch some_foo $ rm some_foo $ touch some_foo $ !rm $ rm some_foo <cursor here>
이 경우 커서는 줄 끝에 위치하며 다시 시작하거나 편집할 수 있습니다.
이 옵션이 마음에 들면 다음 항목에 입력하세요 .bashrc
.
shopt -s histverify
답변2
다음을 수행할 수 있습니다.
fixhist() {
local cmd histnum
cmd=$(HISTTIMEFORMAT=/ history 1)
histnum=$((${cmd%%[*/]*}))
cmd=${cmd#*/} # remove the histnum
case $cmd in
(rm\ *|mv\ *|...)
history -d "$histnum" # delete
history -s "#$cmd" # add back with a #
esac
}
PROMPT_COMMAND=fixhist
아이디어는 각 프롬프트 전에 마지막 기록 항목( history 1
)과 그것이 다음 중 하나인지 여부를 확인하는 것입니다.위험한, 우리는 그것을 삭제하고 ( history -d
) #
로 다시 추가합니다 history -s
.
(물론 설정을 삭제해야 합니다 HISTIGNORE
.)
그러나 원치 않는 부작용 중 하나는 그것이 변한다는 것입니다.역사적 시간그 중에는 ...명령이 rm
있습니다 mv
.
이 문제를 해결하기 위한 대안은 다음과 같습니다.
fixhist() {
local cmd time histnum
cmd=$(HISTTIMEFORMAT='<%s>' history 1)
histnum=$((${cmd%%[<*]*}))
time=${cmd%%>*}
time=${time#*<}
cmd=${cmd#*>}
case $cmd in
(rm\ *|mv\ *|...)
history -d "$histnum" # delete
HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
esac
}
PROMPT_COMMAND=fixhist
이번에는 마지막 기록 항목의 시간을 기록하고 기록 줄을 다시 추가합니다. history -r
타임스탬프가 포함된 임시 파일을 사용합니다(여기에 설명되어 있음).
fixhist
당신은 당신보다 먼저 실행하고 싶습니다 history -a; history -c; history -r
. 안타깝게도 현재 버전에는 추가한 추가 행이 저장되지 않는 bash
버그가 있습니다 . history -a
해결책은 다음과 같이 작성하는 것입니다.
fixhist() {
local cmd time histnum
cmd=$(HISTTIMEFORMAT='<%s>' history 1)
histnum=$((${cmd%%[<*]*}))
time=${cmd%%>*}
time=${time#*<}
cmd=${cmd#*>}
case $cmd in
(rm\ *|mv\ *|...)
history -d "$histnum" # delete
history -a
[ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
(*)
history -a
esac
history -c
history -r
}
PROMPT_COMMAND=fixhist
즉, 주석 처리된 명령을 HISTFILE이 history -a
수행하도록 허용하는 대신 직접 HISTFILE에 추가합니다.
답변3
이것스테판의 답변을 수락했습니다.정말 대단해. 내가 채택한 방법은 다음과 같습니다. 패턴 일치가 약간 다릅니다.
if
대신 문을 사용하면 case
정규식 일치( )를 사용할 수 있으며 [[ "$cmd" =~ <REGEX> ]]
아래 코드는 다음 논리로 작동합니다.
- 다음과 같은 경우 기록에 추가하지 마세요.
- 명령줄은 2개 이상의 연속 공백으로 시작하거나 끝납니다.
예:<spc><spc>history
- 명령줄은 2개 이상의 연속 공백으로 시작하거나 끝납니다.
- 다음과 같은 경우에 주석이 달린 명령을 추가합니다.
rm
또는mv
cli 스위치로 명령- 명령줄은
:;
공백 하나로 시작하거나;:
다음으로 끝납니다. 예:
rm -R /tmp/somedir
echo "doing something dangerous I don't want to trip by accident";:
여기에는 캐비아도 포함되어 있는데, 예를 들면 다음과 같습니다.
echo ";rm -something"
- 그렇지 않으면 기록에 추가
예:rm somefile
echo ";rm -something"
암호
_history_hook() {
# The code below is from https://unix.stackexchange.com/a/110056/138012
# history builtiun options used: https://www.gnu.org/software/bash/manual/html_node/Bash-History-Builtins.html
# history -a : Append new (mem) lines to history (file)
# history -d : Delete range (mem)
# history -c : Clear history list (mem) ++
# history -r : Read (file) append to (mem) ++
# ++ needed to circumvent a bug issue.
local cmd time histnum
cmd=$(HISTTIMEFORMAT='<%s>' history 1)
histnum=$((${cmd%%[<*]*}))
time="${cmd%%>*}"
time=${time#*<}
cmd="${cmd#*>}"
# different behaviors for different patterns
if [[ "$cmd" =~ ^\ \ +.*|\ +\ $ ]]; then
# delete only (two spaces - leading or trailing)
history -d "$histnum" # delete
elif [[ "$cmd" =~ ((^|;[[:space:]]*)(rm|mv)\ +-)|^\ |^:\;|\;:$ ]]; then
# rewrite history as a 'safe version'
history -d "$histnum" # delete
history -a
[ -f "$HISTFILE" ] && printf '# %s\n' "$time" "$cmd" >> "$HISTFILE"
else
# append 'as usual'
history -a
fi
# rewriting history file
history -c
history -r
}
export HISTCONTROL=erasedups # This does not seem to work right now - need to fix this
export PROMPT_COMMAND="$PROMPT_COMMAND; _history_hook"