bash_history: 위험한 명령 주석 처리: `#`

bash_history: 위험한 명령 주석 처리: `#`

"위험한" 명령이 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을 덮어씁니다.UpENTERlscat /dev/foo > file.out

#내가 달성하고 싶은 것은 실행되지 않도록 cat 명령 앞에 a를 두는 것입니다 . 그러나 기록에서는 계속 볼 수 있으며 주석을 제거하여 재사용할 수 있습니다(긴 명령인 경우).

답변1

귀하의 질문에 정확하게 답변하지는 않지만 귀하의 문제에 대한 대체 솔루션을 제공할 수도 있습니다.

내가 올바르게 이해했다면, 입력하는 동안 발생할 수 있는 실수에 대해 걱정하고 계시는 것입니다. 예를 들어 기록의 이전 명령이 유지하고 싶은 항목을 삭제한 !rm경우입니다 .rm

이 경우에는 좋은세게 때리다옵션은 입니다 histverify. shopt -s histverifybang 으로 명령을 호출 하면 !즉시 실행되지 않고 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
  • 다음과 같은 경우에 주석이 달린 명령을 추가합니다.
    • rm또는 mvcli 스위치로 명령
    • 명령줄은 :;공백 하나로 시작하거나 ;:
      다음으로 끝납니다. 예:
    • 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"

관련 정보