답변:
기본적으로는 아니지만 DEBUG
트랩 을 사용하여 해킹 할 수 있습니다 . 이 코드 는 zsh와 유사하게 설정 preexec
및 precmd
기능합니다. 명령 행은에 단일 인수로 전달됩니다 preexec
.
다음은 precmd
각 명령을 실행하기 전에 실행되는 기능 을 설정하기위한 간단한 코드 버전입니다 .
preexec () { :; }
preexec_invoke_exec () {
[ -n "$COMP_LINE" ] && return # do nothing if completing
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`;
preexec "$this_command"
}
trap 'preexec_invoke_exec' DEBUG
이 트릭은 Glyph Lefkowitz 때문입니다 . 원래 저자를 찾은 bcat 에게 감사합니다 .
편집하다. https://github.com/rcaloras/bash-preexec 에서 Glyph의 해킹 업데이트 버전을 확인할 수 있습니다.
"$BASH_COMMAND" = "$PROMPT_COMMAND"
비교는 나를 위해 작동하지 않습니다 i.imgur.com/blneCdQ.png
time for i in {1..10}; do true; done
데 DEBUG 트랩을 활성화 한 후 보통 0.040 초, 1.400 ~ 1.600 초가 소요됩니다. 이로 인해 트랩 명령이 루프 당 두 번 실행됩니다. Cygwin에서는 sed를 실행하는 데 필요한 포크 속도가 포크 만 약 0.030 초로 엄청나게 느려집니다 ( echo
내장과 속도 차이 /bin/echo
). 명심해야 할 것.
PROMPT_COMMAND
변수에 더 많은 명령이있는 경우 (예 :로 구분 ;
) 다음 preexec_invoke_exec
과 같이 함수 의 두 번째 줄에서 패턴 일치를 사용해야 [[ "$PROMPT_COMMAND" =~ "$BASH_COMMAND" ]]
합니다. BASH_COMMAND
각 명령을 개별적으로 나타 내기 때문 입니다.
에서 trap
명령을 사용할 수 있습니다 help trap
.
SIGNAL_SPEC가 DEBUG이면 모든 간단한 명령 전에 ARG가 실행됩니다.
예를 들어, 터미널 제목을 동적으로 변경하려면 다음을 사용할 수 있습니다.
trap 'echo -e "\e]0;$BASH_COMMAND\007"' DEBUG
에서 이 소스.
help trap
은 "SIGNAL_SPEC가 DEBUG이면 모든 간단한 명령 후에 ARG가 실행된다"고 말합니다 .
trap '[ -n "$COMP_LINE" ] && [ "$BASH_COMMAND" != "$PROMPT_COMMAND" ] && date "+%X";echo -e "\e]0;$BASH_COMMAND\007"' DEBUG
. 이것은 명령을 제목에 넣고 모든 명령 바로 전에 현재 시간을 인쇄하지만 실행할 때 그렇게하지 않습니다 $PROMPT_COMMAND
.
[ -z "$COMP_LINE" ]
.
실행되는 쉘 함수는 아니지만 $PS0
각 명령을 실행하기 전에 표시 되는 프롬프트 문자열을 제공했습니다 . 자세한 내용은 http://stromberg.dnsalias.org/~strombrg/PS0-prompt/
$PS0
bash
4.4에 포함되어 있지만 대부분의 Linux에서 4.4를 포함하는 데 시간이 오래 걸립니다. 원하는 경우 4.4를 직접 빌드 할 수 있습니다. 이 경우, 당신은 아마 아래에 넣어해야 /usr/local
,에 추가 /etc/shells
하고 chsh
그것. 그런 다음, 로그 아웃했다가 다시 로그인하여, 아마도 ssh
yourself @ localhost su
에 테스트 하거나 먼저 자신에게 테스트하십시오.
나는 최근에 내 측면 프로젝트 에서이 정확한 문제를 해결해야했습니다. bash에 대한 zsh의 preexec 및 precmd 기능을 에뮬레이트하는 상당히 강력하고 탄력적 인 솔루션을 만들었습니다.
https://github.com/rcaloras/bash-preexec
원래 Glyph Lefkowitz의 솔루션을 기반으로했지만 개선되어 최신 상태로 유지되었습니다. 필요한 경우 기꺼이 도움을 주거나 기능을 추가하십시오.
힌트 주셔서 감사합니다! 나는 이것을 사용하여 끝났다.
#created by francois scheurer
#sourced by '~/.bashrc', which is the last runned startup script for bash invocation
#for login interactive, login non-interactive and non-login interactive shells.
#note that a user can easily avoid calling this file by using options like '--norc';
#he also can unset or overwrite variables like 'PROMPT_COMMAND'.
#therefore it is useful for audit but not for security.
#prompt & color
#http://www.pixelbeat.org/docs/terminal_colours/#256
#http://www.frexx.de/xterm-256-notes/
_backnone="\e[00m"
_backblack="\e[40m"
_backblue="\e[44m"
_frontred_b="\e[01;31m"
_frontgreen_b="\e[01;32m"
_frontgrey_b="\e[01;37m"
_frontgrey="\e[00;37m"
_frontblue_b="\e[01;34m"
PS1="\[${_backblue}${_frontgreen_b}\]\u@\h:\[${_backblack}${_frontblue_b}\]\w\\$\[${_backnone}${_frontgreen_b}\] "
#'history' options
declare -rx HISTFILE="$HOME/.bash_history"
chattr +a "$HISTFILE" # set append-only
declare -rx HISTSIZE=500000 #nbr of cmds in memory
declare -rx HISTFILESIZE=500000 #nbr of cmds on file
declare -rx HISTCONTROL="" #does not ignore spaces or duplicates
declare -rx HISTIGNORE="" #does not ignore patterns
declare -rx HISTCMD #history line number
history -r #to reload history from file if a prior HISTSIZE has truncated it
if groups | grep -q root; then declare -x TMOUT=3600; fi #timeout for root's sessions
#enable forward search (ctrl-s)
#http://ruslanspivak.com/2010/11/25/bash-history-incremental-search-forward/
stty -ixon
#history substitution ask for a confirmation
shopt -s histverify
#add timestamps in history - obsoleted with logger/syslog
#http://www.thegeekstuff.com/2008/08/15-examples-to-master-linux-command-line-history/#more-130
#declare -rx HISTTIMEFORMAT='%F %T '
#bash audit & traceabilty
#
#
declare -rx AUDIT_LOGINUSER="$(who -mu | awk '{print $1}')"
declare -rx AUDIT_LOGINPID="$(who -mu | awk '{print $6}')"
declare -rx AUDIT_USER="$USER" #defined by pam during su/sudo
declare -rx AUDIT_PID="$$"
declare -rx AUDIT_TTY="$(who -mu | awk '{print $2}')"
declare -rx AUDIT_SSH="$([ -n "$SSH_CONNECTION" ] && echo "$SSH_CONNECTION" | awk '{print $1":"$2"->"$3":"$4}')"
declare -rx AUDIT_STR="[audit $AUDIT_LOGINUSER/$AUDIT_LOGINPID as $AUDIT_USER/$AUDIT_PID on $AUDIT_TTY/$AUDIT_SSH]"
declare -rx AUDIT_SYSLOG="1" #to use a local syslogd
#
#PROMPT_COMMAND solution is working but the syslog message are sent *after* the command execution,
#this causes 'su' or 'sudo' commands to appear only after logouts, and 'cd' commands to display wrong working directory
#http://jablonskis.org/2011/howto-log-bash-history-to-syslog/
#declare -rx PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p user.info -t "$AUDIT_STR $PWD")' #avoid subshells here or duplicate execution will occurs!
#
#another solution is to use 'trap' DEBUG, which is executed *before* the command.
#http://superuser.com/questions/175799/does-bash-have-a-hook-that-is-run-before-executing-a-command
#http://www.davidpashley.com/articles/xterm-titles-with-bash.html
#set -o functrace; trap 'echo -ne "===$BASH_COMMAND===${_backvoid}${_frontgrey}\n"' DEBUG
set +o functrace #disable trap DEBUG inherited in functions, command substitutions or subshells, normally the default setting already
#enable extended pattern matching operators
shopt -s extglob
#function audit_DEBUG() {
# echo -ne "${_backnone}${_frontgrey}"
# (history -a >(logger -p user.info -t "$AUDIT_STR $PWD" < <(tee -a ~/.bash_history))) && sync && history -c && history -r
# #http://stackoverflow.com/questions/103944/real-time-history-export-amongst-bash-terminal-windows
# #'history -c && history -r' force a refresh of the history because 'history -a' was called within a subshell and therefore
# #the new history commands that are appent to file will keep their "new" status outside of the subshell, causing their logging
# #to re-occur on every function call...
# #note that without the subshell, piped bash commands would hang... (it seems that the trap + process substitution interfer with stdin redirection)
# #and with the subshell
#}
##enable trap DEBUG inherited for all subsequent functions; required to audit commands beginning with the char '(' for a subshell
#set -o functrace #=> problem: completion in commands avoid logging them
function audit_DEBUG() {
#simplier and quicker version! avoid 'sync' and 'history -r' that are time consuming!
if [ "$BASH_COMMAND" != "$PROMPT_COMMAND" ] #avoid logging unexecuted commands after Ctrl-C or Empty+Enter
then
echo -ne "${_backnone}${_frontgrey}"
local AUDIT_CMD="$(history 1)" #current history command
#remove in last history cmd its line number (if any) and send to syslog
if [ -n "$AUDIT_SYSLOG" ]
then
if ! logger -p user.info -t "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])[^0-9])*( )}"
then
echo error "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])[^0-9])*( )}"
fi
else
echo $( date +%F_%H:%M:%S ) "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])[^0-9])*( )}" >>/var/log/userlog.info
fi
fi
#echo "===cmd:$BASH_COMMAND/subshell:$BASH_SUBSHELL/fc:$(fc -l -1)/history:$(history 1)/histline:${AUDIT_CMD%%+([^ 0-9])*}===" #for debugging
}
function audit_EXIT() {
local AUDIT_STATUS="$?"
if [ -n "$AUDIT_SYSLOG" ]
then
logger -p user.info -t "$AUDIT_STR" "#=== bash session ended. ==="
else
echo $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== bash session ended. ===" >>/var/log/userlog.info
fi
exit "$AUDIT_STATUS"
}
#make audit trap functions readonly; disable trap DEBUG inherited (normally the default setting already)
declare -fr +t audit_DEBUG
declare -fr +t audit_EXIT
if [ -n "$AUDIT_SYSLOG" ]
then
logger -p user.info -t "$AUDIT_STR" "#=== New bash session started. ===" #audit the session openning
else
echo $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== New bash session started. ===" >>/var/log/userlog.info
fi
#when a bash command is executed it launches first the audit_DEBUG(),
#then the trap DEBUG is disabled to avoid a useless rerun of audit_DEBUG() during the execution of pipes-commands;
#at the end, when the prompt is displayed, re-enable the trap DEBUG
declare -rx PROMPT_COMMAND="trap 'audit_DEBUG; trap DEBUG' DEBUG"
declare -rx BASH_COMMAND #current command executed by user or a trap
declare -rx SHELLOPT #shell options, like functrace
trap audit_EXIT EXIT #audit the session closing
즐겨!
패치 또는 특수 실행 도구를 사용하지 않고 모든 'bash'명령 / 내장 파일을 텍스트 파일 또는 'syslog'서버에 기록하는 방법을 작성했습니다.
'bash'를 초기화 할 때 한 번 호출해야하는 간단한 셸 스크립트이므로 배포하기가 매우 쉽습니다.
PS0
동작을 수행PS1
하지만 명령을 읽은 후 실행하기 전에 사용되는 변수가 있습니다. gnu.org/software/bash/manual/bashref.html#Bash-Variables