มีฟังก์ชั่นมากมายที่สามารถใช้ใน Bash shell ได้ คำจำกัดความของพวกเขาสามารถแสดงรายการโดยset
แต่วิธีการค้นหาในไฟล์ที่ฟังก์ชั่นบางอย่างที่ผู้ใช้กำหนดจะถูกกำหนด?
มีฟังก์ชั่นมากมายที่สามารถใช้ใน Bash shell ได้ คำจำกัดความของพวกเขาสามารถแสดงรายการโดยset
แต่วิธีการค้นหาในไฟล์ที่ฟังก์ชั่นบางอย่างที่ผู้ใช้กำหนดจะถูกกำหนด?
คำตอบ:
เปิดการดีบัก จากคู่มือ Bash :
extdebug
หากตั้งค่าไว้ที่การเรียกใช้เชลล์หรือในไฟล์เริ่มทำงานเชลล์ให้จัดเรียงเพื่อดำเนินการโปรไฟล์ดีบักเกอร์ก่อนที่เชลล์จะเริ่มต้นซึ่งเหมือนกับ
--debugger
ตัวเลือก หากตั้งค่าหลังจากการเรียกใช้จะมีการเปิดใช้งานลักษณะการทำงานที่ debuggers ใช้:
-F
ตัวเลือกไปdeclare
ในตัว (ดูทุบตี builtins ) แสดงชื่อแฟ้มแหล่งที่มาและจำนวนบรรทัดที่สอดคล้องกับชื่อฟังก์ชันแต่ละจำหน่ายเป็นอาร์กิวเมนต์
ตัวอย่าง:
$ bash --debugger
$ declare -Ff quote
quote 143 /usr/share/bash-completion/bash_completion
และแน่นอน:
$ nl -ba /usr/share/bash-completion/bash_completion | sed -n 143,150p
143 quote()
144 {
145 local quoted=${1//\'/\'\\\'\'}
146 printf "'%s'" "$quoted"
147 }
148
149 # @see _quote_readline_by_ref()
150 quote_readline()
shopt -s extdebug; declare -Ff quote; shopt -u extdebug
ในฐานะที่เป็นตัวอย่างของคุณมันไม่จำเป็นแม้จะเริ่มต้นเปลือกใหม่:
find_function()( shopt -s extdebug; declare -F "$@"; )
คุณสามารถทำให้เรื่องนี้เป็นฟังก์ชั่นเช่นนี้ ด้วย parens บนเนื้อหาของฟังก์ชันมันจะถูกดำเนินการใน subshell และการเปลี่ยนแปลงใน shopts จะไม่ส่งผลกระทบต่อผู้โทร และ-f
ดูเหมือนจะไม่ต้องการ
อันที่จริงแล้วมันซับซ้อนกว่าที่ปรากฏในตอนแรก ไฟล์ใดที่เชลล์ของคุณอ่านขึ้นอยู่กับชนิดของเชลล์ที่คุณใช้งานอยู่ในปัจจุบัน ไม่ว่าจะเป็นแบบโต้ตอบหรือไม่ไม่ว่าจะเป็นเข้าสู่ระบบหรือเปลือกที่ไม่ใช่การเข้าสู่ระบบและสิ่งที่รวมกันของข้างต้น ในการค้นหาไฟล์เริ่มต้นทั้งหมดที่เชลล์สามารถอ่านได้คุณสามารถทำได้ (เปลี่ยน$functionName
เป็นชื่อจริงของฟังก์ชั่นที่คุณกำลังมองหา):
grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
~/.bash_aliases /etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
หากไม่ได้ทำงานคุณอาจจะเรียกไฟล์ที่ไม่ได้เริ่มต้นใช้หรือนามแฝงของมัน.
source
หากต้องการค้นหากรณีดังกล่าวให้เรียกใช้:
grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
/etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
นั่นอาจต้องการคำอธิบายบางอย่าง -P
ช่วยให้สามารถใช้งานร่วม Perl นิพจน์ปกติ (PCRE) ซึ่งให้เราใช้บางคนชอบเล่น regex ไวยากรณ์ โดยเฉพาะ:
(^|\s)
: จับคู่ส่วนต้นของบรรทัด ( ^
) หรือช่องว่าง ( \s
)(\.|source)\s+
: จับคู่ทั้งตัว.
อักษร ( \.
) หรือคำsource
แต่หากพวกเขาตามด้วยตัวอักษรช่องว่างอย่างน้อยหนึ่งตัวนี่คือสิ่งที่ทำให้ฉันในระบบของฉัน:
$ grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
> ~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
> /etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
/home/terdon/.bashrc: . /etc/bashrc
/home/terdon/.bashrc: . /etc/bash_completion
/home/terdon/.bashrc:. $HOME/scripts/git-prompt.sh
/home/terdon/.bashrc:# echo -n "$n : "; grep "^CA" $n |perl -e 'my ($a,$c)=0; while(<>){$c++;next if /cellular_component_unknown/; next if /biological_process/; $a++} print "$a Classes of $c annotated (" . $a*100/$c . ")\n"'
/etc/bash.bashrc:[ -r /usr/share/bash-completion/bash_completion ] && . /usr/share/bash-completion/bash_completion
/etc/profile: test -r "$profile" && . "$profile"
/etc/profile: . /etc/bash.bashrc
/etc/profile.d/locale.sh: . "$XDG_CONFIG_HOME/locale.conf"
/etc/profile.d/locale.sh: . "$HOME/.config/locale.conf"
/etc/profile.d/locale.sh: . /etc/locale.conf
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh: . /usr/bin/byobu-launch
อย่างที่คุณเห็นอย่างไรก็ตามสิ่งนี้จะพิมพ์บรรทัดที่ตรงกันทั้งหมด สิ่งที่เราสนใจจริงๆคือรายชื่อไฟล์ที่เรียกว่าไม่ใช่บรรทัดที่เรียกพวกเขา คุณสามารถหาคนที่มีสิ่งนี้ซับซ้อนกว่า regex:
grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
~/.bash.login ~/.bash_aliases \
/etc/bash.bashrc /etc/profile \
/etc/profile.d/* /etc/environment 2> /dev/null
-h
ธงยับยั้งการพิมพ์ชื่อไฟล์ที่การแข่งขันถูกพบซึ่งgrep
ไม่โดยค่าเริ่มต้นเมื่อบอกว่าจะค้นหาผ่านหลายไฟล์ ความ-o
หมาย "พิมพ์เฉพาะส่วนที่ตรงกันของบรรทัด" สิ่งพิเศษที่เพิ่มเข้าไปใน regex คือ:
\K
: ละเว้นสิ่งที่ตรงกับจุดนี้ นี่เป็นเคล็ดลับ PCRE ที่ให้คุณใช้ regex ที่ซับซ้อนเพื่อค้นหาคู่ของคุณ แต่ไม่รวมส่วนที่ตรงกันเมื่อใช้การ-o
ตั้งค่าสถานะgrepในระบบของฉันคำสั่งดังกล่าวจะกลับมา:
$ grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
> ~/.bash.login ~/.bash_aliases \
> /etc/bash.bashrc /etc/profile \
> /etc/profile.d/* /etc/environment 2> /dev/null
/etc/bashrc
/etc/bash_completion
$HOME/scripts/git-prompt.sh
$a*100/$c
")\n"'
/usr/share/bash-completion/bash_completion
"$profile"
/etc/bash.bashrc
"$XDG_CONFIG_HOME/locale.conf"
"$HOME/.config/locale.conf"
/etc/locale.conf
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
โปรดทราบว่าฉันบังเอิญมีการใช้.
พื้นที่ที่ไม่ได้ใช้ในการจัดหา แต่นั่นเป็นเพราะฉันมีนามแฝงที่เรียกภาษาอื่นไม่ใช่ทุบตี นั่นคือสิ่งที่ให้ความแปลก$a*100/$c
และ")\n"'
ในผลลัพธ์ด้านบน แต่ก็สามารถเพิกเฉยได้
ท้ายที่สุดต่อไปนี้คือวิธีรวมทั้งหมดเข้าด้วยกันและค้นหาชื่อฟังก์ชันในไฟล์เริ่มต้นทั้งหมดและไฟล์ทั้งหมดที่ไฟล์เริ่มต้นของคุณกำลังจัดหา:
grep_function(){
target="$@"
files=( ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login
~/.bash_aliases /etc/bash.bashrc /etc/profile
/etc/profile.d/* /etc/environment)
while IFS= read -r file; do
files+=( "$file" )
done < <(grep -hPo '(^|\s)(\.|source)\s+\K\S+' "${files[@]}" 2>/dev/null)
for file in "${files[@]}"; do
## The tilde of ~/ can break this
file=$(sed 's|~/|'"$HOME"'/|g' <<<"$file")
if [[ -e $file ]]; then
grep -H "$target" -- "$file"
fi
done
}
เพิ่มบรรทัดเหล่านั้นในของคุณ~/.bashrc
และคุณสามารถเรียกใช้ (ฉันใช้fooBar
เป็นชื่อฟังก์ชั่นตัวอย่าง):
grep_function fooBar
ตัวอย่างเช่นหากฉันมีบรรทัดนี้ใน~/.bashrc
:
. ~/a
และไฟล์~/a
คือ:
$ cat ~/a
fooBar(){
echo foo
}
ฉันควรหามันด้วย:
$ grep_function fooBar
/home/terdon/a:fooBar(){
+=
array+="foo"
ผนวกสตริงfoo
ไปยังองค์ประกอบที่ 1 ของอาร์เรย์?
ปกติต่อผู้ใช้ dotfile อ่านคือbash
~/.bashrc
อย่างไรก็ตามมันอาจเป็นแหล่งไฟล์อื่น ๆ ได้อย่างดีเช่นฉันต้องการเก็บนามแฝงและฟังก์ชั่นในไฟล์แยกต่างหากที่เรียกว่า~/.bash_aliases
และ~/.bash_functions
ซึ่งทำให้การค้นหาง่ายขึ้นมาก คุณสามารถค้นหา.bashrc
สำหรับsource
คำสั่งด้วย:
grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc
เมื่อคุณมีรายการไฟล์ที่ผู้ใช้สร้างขึ้นคุณสามารถค้นหาไฟล์และผู้ใช้.bashrc
ด้วยการgrep
โทรเพียงครั้งเดียวเช่นฟังก์ชั่นfoo
สำหรับการตั้งค่าของฉัน:
grep foo /home/USERNAME/.bash{rc,_aliases,_functions}