বাশের কি কোনও হুক আছে যা কমান্ড কার্যকর করার আগে চালিত হয়?


111

ব্যাশে, আমি কমান্ড চালানোর ঠিক আগে কোনও ফাংশন সম্পাদন করার ব্যবস্থা করতে পারি?

এখানে রয়েছে $PROMPT_COMMANDযা একটি প্রম্পট দেখানোর আগেই কার্যকর করা হয়, যেমন কমান্ড চালানোর ঠিক পরে after

বাশ এর $PROMPT_COMMANDzsh এর precmdকার্যকারিতা অনুসারে; সুতরাং আমি যা খুঁজছি তা zsh এর সমতুল্য বাশ preexec

অ্যাপ্লিকেশনগুলির উদাহরণ: কার্যকর হওয়া কমান্ডের জন্য আপনার টার্মিনাল শিরোনাম সেট করুন; timeপ্রতিটি কমান্ডের আগে স্বয়ংক্রিয়ভাবে যুক্ত করুন ।


3
বাশ সংস্করণ 4.4 এর একটি PS0ভেরিয়েবল রয়েছে যা কাজ করে PS1তবে কমান্ডটি পড়ার পরে ব্যবহার করা হয় তবে তা কার্যকর করার আগে। Gnu.org/software/bash/manual/bashref.html#Bash- ভেরিয়েবলগুলি
গ্লেন জ্যাকম্যান

উত্তর:


93

স্থানীয়ভাবে নয়, তবে DEBUGফাঁদ ব্যবহার করে এটি হ্যাক করা যায় । এই কোডটি zsh এর অনুরূপ সেট আপ preexecএবং precmdফাংশন করে। কমান্ড লাইনটি একক যুক্তি হিসাবে পাস করা হয়েছে preexec

এখানে precmdপ্রতিটি কমান্ড চালানোর আগে কার্যকর করা একটি ফাংশন সেট আপ করার জন্য কোডটির একটি সরল সংস্করণ দেওয়া আছে is

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

এই কৌশলটি গ্লাইফ লেফকোভিটসের কারণে ; মূল লেখক সনাক্ত করার জন্য বিসিএটি ধন্যবাদ ।

সম্পাদনা করুন। গ্লাইফের হ্যাকের একটি আপডেট সংস্করণ এখানে পাওয়া যাবে: https://github.com/rcaloras/bash-preexec


"$BASH_COMMAND" = "$PROMPT_COMMAND"তুলনা আমার জন্য কাজ না করে i.imgur.com/blneCdQ.png
laggingreflex

2
আমি সাইগউইনে এই কোডটি ব্যবহার করার চেষ্টা করেছি। দুঃখজনকভাবে এটির সেখানে বেশ তীব্র পারফরম্যান্সের প্রভাব রয়েছে - একটি সাধারণ বেঞ্চমার্ক কমান্ডটি চালানোর জন্য time for i in {1..10}; do true; doneসাধারণত 0.040 সেকেন্ড এবং ডিইবিইউজি ট্র্যাপটি সক্রিয় করার পরে 1.400 থেকে 1.600 সেকেন্ড লাগে। এটি ট্রুপ কমান্ডটি প্রতি লুপের জন্য দুবার কার্যকর করা যায় - এবং সাইগউইনের উপর সেড চালানোর জন্য প্রয়োজনীয় কাঁটাচামচ একা কাঁটাচামড়ার জন্য প্রায় 0.030 সেকেন্ডে বিরতিযুক্তভাবে ধীর হয় ( echoবিল্টিন এবং এর মধ্যে গতির পার্থক্য /bin/echo)। কিছু মনে রাখতে হবে।
কেডিবি

2
কাঁটা চুষার জন্য @ কেডিবি সাইগউইনের অভিনয়। আমার বোধগম্যতা এটি উইন্ডোজে অনিবার্য। আপনার যদি উইন্ডোজটিতে বাশ কোড চালানোর দরকার হয় তবে কাঁটাচামচ কাটা চেষ্টা করুন।
গিলস

@ ডেভনুল এই ফাঁদটি সরিয়ে খুব সহজেই তা ছড়িয়ে দেওয়া যেতে পারে। লোকেদের যা করার অনুমতি দেওয়া হয়েছে তা করার কিন্তু তাদের করা উচিত নয় এমন করার কোনও প্রযুক্তিগত সমাধান নেই। আংশিক প্রতিকার রয়েছে: যত বেশি লোককে তত বেশি অ্যাক্সেস দেবেন না, আপনার ব্যাকআপগুলি আপ-টু-ডেট রয়েছে তা নিশ্চিত করুন, সরাসরি ফাইল ম্যানিপুলেশন না করে সংস্করণ নিয়ন্ত্রণ ব্যবহার করুন,… আপনি যদি এমন কিছু চান যা ব্যবহারকারীরা সহজেই অক্ষম করতে না পারে তবে আসুন একা কিছুতেই অক্ষম করতে পারবেন না, তবে শেলের মধ্যে থাকা বিধিনিষেধগুলি আপনাকে সহায়তা করবে না: এগুলি যুক্ত করা যেতে পারে সেগুলি সহজেই সরানো যেতে পারে।
গিলস

1
আপনি যদি একটি আরও কমান্ড থাকে PROMPT_COMMANDপরিবর্তনশীল (যেমন দ্বারা সীমায়িত ;), আপনি দ্বিতীয় লাইনে প্যাটার্ন ম্যাচিং ব্যবহার করতে হবে পারে preexec_invoke_execশুধু ভালো ফাংশন: [[ "$PROMPT_COMMAND" =~ "$BASH_COMMAND" ]]। এটি কারণ BASH_COMMANDপ্রতিটি আদেশ পৃথক পৃথকভাবে উপস্থাপন করে।
জিরিস্লাভ

20

আপনি trapকমান্ডটি ব্যবহার করতে পারেন (থেকে help trap):

যদি একটি SIGNAL_SPEC DEBUG হয়, প্রতিটি সাধারণ কমান্ডের আগে ARG কার্যকর করা হয়।

উদাহরণস্বরূপ, গতিশীলভাবে টার্মিনাল শিরোনাম পরিবর্তন করতে আপনি ব্যবহার করতে পারেন:

trap 'echo -e "\e]0;$BASH_COMMAND\007"' DEBUG

এই উত্স থেকে ।


1
আকর্ষণীয় ... আমার পুরানো উবুন্টু সার্ভারে, help trapবলেছেন "যদি একটি সিগন্যাল_স্পেক ডিইবিইউজি হয়, তবে প্রতিটি সাধারণ কমান্ডের পরে এআরজি কার্যকর করা হয়" [জোর আমার]।
লার্শ

1
আমি গৃহীত উত্তরে বিশেষ কাপড় মধ্যে কয়েকটির সাথে এই উত্তরটি সংমিশ্রণ ব্যবহৃত: trap '[ -n "$COMP_LINE" ] && [ "$BASH_COMMAND" != "$PROMPT_COMMAND" ] && date "+%X";echo -e "\e]0;$BASH_COMMAND\007"' DEBUG। এটি কমান্ডটি শিরোনামে রাখে এবং প্রতিটি কমান্ডের ঠিক আগে বর্তমান সময়ের মুদ্রণ করে, কিন্তু কার্যকর করার সময় তা করে না $PROMPT_COMMAND
coredumperror

1
@CoreDumpError, যেহেতু আপনি কোড রি-ফ্যাক্টর থাকেন আপনার সমস্ত অবস্থার অস্বীকার করা উচিত: প্রথম এক অত: পর হয়ে: [ -z "$COMP_LINE" ]
সিউরাস

ইউরোস ধন্যবাদ! সমস্যাটি লক্ষ্য করার জন্য আমি প্রায় পর্যাপ্ত বাশ প্রোগ্রামিং জানি না।
coredumperror

@ লার্শ: আপনার কোন সংস্করণ রয়েছে? আমার কাছে BASH_VERSION = "4.3.11 (1) -রেলিজ" আছে এবং এটিতে " প্রতিটি সাধারণ কমান্ডের আগে এআরজি কার্যকর করা হয় ।"
musiphil

12

এটি চালিত হওয়া শেল ফাংশন নয়, তবে আমি $PS0প্রতিটি কমান্ড চালানোর আগে প্রদর্শিত একটি প্রম্পট স্ট্রিং অবদান রেখেছি । বিশদ এখানে: http://stromberg.dnsalias.org/~strombrg/PS0-prompt/

$PS0bash৪.৪-তে অন্তর্ভুক্ত করা হয়েছে , যদিও বেশিরভাগ লিনাক্সকে ৪.৪ অন্তর্ভুক্ত করতে কিছুটা সময় লাগবে - আপনি চাইলেও নিজেকে ৪.৪ তৈরি করতে পারবেন; সেই ক্ষেত্রে, আপনি সম্ভবত এটি অধীন করা উচিত /usr/local, এটি যোগ /etc/shellsএবং chshএটি। তারপরে লগ আউট এবং পিছনে প্রবেশ করুন, সম্ভবত sshনিজের কাছে @ লোকালহোস্টে নিজেকে যুক্ত করা বা suপরীক্ষা হিসাবে নিজেকে প্রথমে আইএনজি করুন।


11

আমার সম্প্রতি একটি পাশের প্রকল্পের জন্য আমাকে এই সঠিক সমস্যাটি সমাধান করতে হয়েছিল। আমি একটি মোটামুটি দৃust় এবং স্থিতিস্থাপক সমাধান তৈরি করেছি যা বাশের জন্য zsh এর প্রিজেক্স এবং প্রাকম কার্যকারিতা অনুকরণ করে।

https://github.com/rcaloras/bash-preexec

এটি মূলত গ্লিফ লেফকোভিটসের সমাধানের ভিত্তিতে তৈরি হয়েছিল, তবে আমি এটির উন্নতি করেছি এবং এটি আপডেট করেছি। প্রয়োজনে সহায়তা করতে বা কোনও বৈশিষ্ট্য যুক্ত করতে পেরে খুশি।


3

ইঙ্গিতগুলির জন্য আপনাকে ধন্যবাদ! আমি এটি ব্যবহার করে শেষ করেছি:

#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

উপভোগ করুন!


স্তব্ধ হয়ে গেছে এমন পাইপযুক্ত বাশ কমান্ডগুলির সাথে আমার একটি সমস্যা ছিল ... আমি একটি সাবসেল ব্যবহার করে একটি কাজ পেয়েছি, কিন্তু এর ফলে 'ইতিহাস -a' সাবসেলের সুযোগের বাইরে ইতিহাস রিফ্রেশ না করে ... অবশেষে সমাধানটি একটি ফাংশন ব্যবহার করা ছিল সাবসেল কার্যকর করার পরে ইতিহাসটি পুনরায় পড়ুন। আমি যেমন চেয়েছিলাম তেমন কাজ করে। বৈদাস যেমন jablonskis.org/2011/howto-log-bash-history-to-syslog এ লিখেছেন, সি- তে বাশ প্যাচানোর চেয়ে মোতায়েন করা আরও সহজ (আমি অতীতেও এটি করেছি)। তবে প্রতিবারের ইতিহাসের ফাইলটি পুনরায় পড়ার সময় এবং একটি ডিস্ক 'সিঙ্ক' করার সময় কিছুটা পারফরম্যান্স ড্রপ হয় ...
ফ্র্যাঙ্কোইস স্কিচারার

5
আপনি এই কোডটি ছাঁটাই করতে চাইতে পারেন; বর্তমানে এটি প্রায় সম্পূর্ণ অপঠনযোগ্য।
l0b0

3

আমি কোনও প্যাচ বা একটি বিশেষ এক্সিকিউটেবল সরঞ্জাম ব্যবহার না করে সমস্ত 'বাশ' কমান্ড / বিল্টিনগুলিকে কোনও টেক্সট-ফাইল বা 'সিসলগ' সার্ভারে লগ করার জন্য একটি পদ্ধতি লিখেছিলাম।

এটি মোতায়েন করা খুব সহজ, কারণ এটি একটি সাধারণ শেলসক্রিপ্ট যা 'বাশ' এর সূচনাতে একবার কল করা দরকার।

পদ্ধতিটি এখানে দেখুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.