ฉันต้องการที่จะset -x
จุดเริ่มต้นของสคริปต์ของฉันและ "ยกเลิก" มัน (กลับไปยังรัฐก่อนที่ผมตั้งไว้) +x
หลังจากนั้นแทนสุ่มสี่สุ่มห้าการตั้งค่า เป็นไปได้ไหม
PS: ฉันตรวจสอบแล้วที่นี่ ; ที่ดูเหมือนจะไม่ตอบคำถามเท่าที่ฉันจะบอกได้
ฉันต้องการที่จะset -x
จุดเริ่มต้นของสคริปต์ของฉันและ "ยกเลิก" มัน (กลับไปยังรัฐก่อนที่ผมตั้งไว้) +x
หลังจากนั้นแทนสุ่มสี่สุ่มห้าการตั้งค่า เป็นไปได้ไหม
PS: ฉันตรวจสอบแล้วที่นี่ ; ที่ดูเหมือนจะไม่ตอบคำถามเท่าที่ฉันจะบอกได้
คำตอบ:
เพื่อย้อนกลับเพียงแค่ดำเนินการset -x
set +x
ส่วนใหญ่เวลาที่กลับของสตริงนั้นset -str
เป็นสายเดียวกันกับ:+
set +str
โดยทั่วไปในการกู้คืนerrexit
ตัวเลือกเชลล์ทั้งหมด (อ่านด้านล่างเกี่ยวกับ bash ) (เปลี่ยนด้วยset
คำสั่ง) คุณสามารถทำได้ (อ่านด้านล่างเกี่ยวกับshopt
ตัวเลือกbash ):
oldstate="$(set +o); set -$-" # POSIXly store all set options.
.
.
set -vx; eval "$oldstate" # restore all options stored.
คำสั่งนี้:
shopt -po xtrace
จะสร้างสตริงปฏิบัติการที่สะท้อนถึงสถานะของตัวเลือก การp
ตั้งค่าสถานะหมายถึงการพิมพ์และการo
ตั้งค่าสถานะระบุว่าเรากำลังถามเกี่ยวกับตัวเลือกที่กำหนดโดยset
คำสั่ง (ตรงข้ามกับตัวเลือกที่กำหนดโดยshopt
คำสั่ง) คุณสามารถกำหนดสตริงนี้ให้กับตัวแปรและดำเนินการตัวแปรที่ท้ายสคริปต์ของคุณเพื่อกู้คืนสถานะเริ่มต้น
# store state of xtrace option.
tracestate="$(shopt -po xtrace)"
# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"
# restore the value of xtrace to its original value.
eval "$tracestate"
วิธีนี้ใช้ได้กับหลายตัวเลือกพร้อมกัน:
oldstate="$(shopt -po xtrace noglob errexit)"
# change options as needed
set -x
set +x
set -f
set -e
set -x
# restore to recorded state:
set +vx; eval "$oldstate"
การเพิ่มset +vx
หลีกเลี่ยงการพิมพ์รายการตัวเลือกแบบยาว
และถ้าคุณไม่แสดงชื่อตัวเลือกใด ๆ
oldstate="$(shopt -po)"
มันให้คุณค่าของตัวเลือกทั้งหมด และถ้าคุณปล่อยให้o
ธงคุณสามารถทำสิ่งเดียวกันกับshopt
ตัวเลือก:
# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"
# store state of all options.
oldstate="$(shopt -p)"
หากคุณต้องการทดสอบว่ามีการset
ตั้งค่าตัวเลือกหรือไม่วิธีที่ใช้สำนวนที่สุด (Bash) คือ:
[[ -o xtrace ]]
ซึ่งดีกว่าการทดสอบที่คล้ายกันอีกสองแบบ:
[[ $- =~ x ]]
[[ $- == *x* ]]
ด้วยการทดสอบใด ๆ งานนี้:
# record the state of the xtrace option in ts (tracestate):
[ -o xtrace ] && ts='set -x' || ts='set +x'
# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"
# set the xtrace option back to what it was.
eval "$ts"
ต่อไปนี้เป็นวิธีทดสอบสถานะของshopt
ตัวเลือก:
if shopt -q dotglob
then
# dotglob is set, so “echo .* *” would list the dot files twice.
echo *
else
# dotglob is not set. Warning: the below will list “.” and “..”.
echo .* *
fi
โซลูชันที่ใช้งานง่าย POSIX ที่ใช้ในการจัดเก็บตัวset
เลือกทั้งหมดคือ:
set +o
ซึ่งอธิบายไว้ในมาตรฐาน POSIXเป็น:
+ o
เขียนการตั้งค่าตัวเลือกปัจจุบันไปยังเอาต์พุตมาตรฐานในรูปแบบที่เหมาะสมสำหรับการใส่เข้าไปในเชลล์ใหม่เป็นคำสั่งที่ใช้การตั้งค่าตัวเลือกเดียวกัน
ดังนั้นเพียงแค่:
oldstate=$(set +o)
จะรักษาค่าสำหรับตัวเลือกทั้งหมดที่ตั้งค่าโดยใช้set
คำสั่ง
การกู้คืนตัวเลือกต่าง ๆ ให้เป็นค่าดั้งเดิมนั้นเป็นเรื่องของการใช้งานตัวแปร:
set +vx; eval "$oldstate"
shopt -po
ตรงนี้เป็นเทียบเท่ากับการใช้ทุบตีของ หมายเหตุว่ามันจะไม่ครอบคลุมทั้งหมดที่เป็นไปได้ทุบตีshopt
ตัวเลือกเป็นบางส่วนของผู้ที่ถูกกำหนดโดย
มีตัวเลือกเปลือกอื่น ๆ อีกมากมายที่ระบุไว้shopt
ในทุบตี:
$ shopt
autocd off
cdable_vars off
cdspell off
checkhash off
checkjobs off
checkwinsize on
cmdhist on
compat31 off
compat32 off
compat40 off
compat41 off
compat42 off
compat43 off
complete_fullquote on
direxpand off
dirspell off
dotglob off
execfail off
expand_aliases on
extdebug off
extglob off
extquote on
failglob off
force_fignore on
globasciiranges off
globstar on
gnu_errfmt off
histappend on
histreedit off
histverify on
hostcomplete on
huponexit off
inherit_errexit off
interactive_comments on
lastpipe on
lithist off
login_shell off
mailwarn off
no_empty_cmd_completion off
nocaseglob off
nocasematch off
nullglob off
progcomp on
promptvars on
restricted_shell off
shift_verbose off
sourcepath on
xpg_echo off
สิ่งเหล่านี้สามารถผนวกเข้ากับตัวแปรที่ตั้งไว้ด้านบนและเรียกคืนในลักษณะเดียวกัน
$ oldstate="$oldstate;$(shopt -p)"
.
. # change options as needed.
.
$ eval "$oldstate"
มันเป็นไปได้ที่จะทำ (คน$-
ถูกผนวกเพื่อให้แน่ใจว่าerrexit
จะถูกรักษาไว้):
oldstate="$(shopt -po; shopt -p); set -$-"
set +vx; eval "$oldstate" # use to restore all options.
หมายเหตุ : แต่ละเชลล์มีวิธีที่แตกต่างกันเล็กน้อยในการสร้างรายการตัวเลือกที่ถูกตั้งค่าหรือไม่ได้ตั้งค่า (ไม่พูดถึงตัวเลือกต่าง ๆ ที่กำหนดไว้) ดังนั้นสตริงจึงไม่สามารถเคลื่อนย้ายได้ระหว่างเชลล์ แต่จะใช้ได้สำหรับเชลล์ตัวเดียวกัน
zsh
ยังทำงานได้อย่างถูกต้อง (ติดตาม POSIX) ตั้งแต่รุ่น 5.3 ในรุ่นก่อนหน้านั้นตาม POSIX เพียงบางส่วนเท่านั้นโดยset +o
ที่มันพิมพ์ตัวเลือกในรูปแบบที่เหมาะสำหรับการใส่เข้าไปใหม่ในเชลล์เป็นคำสั่ง แต่สำหรับตัวเลือกการตั้งค่าเท่านั้น(ไม่ได้พิมพ์ตัวเลือกยกเลิกการตั้งค่า )
mksh (และตามลำดับ lksh) ยังไม่ (MIRBSD KSH R54 2016/11/11) สามารถทำสิ่งนี้ได้ คู่มือ mksh ประกอบด้วย:
ในรุ่นอนาคตชุด + o จะทำงานตามคำสั่ง POSIX และพิมพ์เพื่อคืนค่าตัวเลือกปัจจุบันแทน
ใน bash ค่าของset -e
( errexit
) จะถูกรีเซ็ตภายในเชลล์ย่อยซึ่งทำให้ยากต่อการดักจับค่าด้วยset +o
เชลล์ย่อย $ (…)
วิธีแก้ปัญหาใช้:
oldstate="$(set +o); set -$-"
ด้วย Almquist shell และอนุพันธ์ ( อย่างน้อยdash
NetBSD / FreeBSD sh
) และ bash
4.4 หรือสูงกว่าคุณสามารถสร้างตัวเลือกในท้องถิ่นให้กับฟังก์ชั่นด้วยlocal -
(ทำ$-
ตัวแปรท้องถิ่นหากคุณต้องการ):
$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
แต่นั่นไม่ได้นำไปใช้กับที่มาไฟล์ แต่คุณสามารถ redefine source
เป็นsource() { . "$@"; }
ในการทำงานรอบที่
ด้วยksh88
การเปลี่ยนแปลงตัวเลือกจะอยู่ภายในฟังก์ชันนั้นตามค่าเริ่มต้น ด้วยksh93
นั่นเป็นเพียงกรณีของฟังก์ชั่นที่กำหนดด้วยfunction f { ...; }
ไวยากรณ์ (และการกำหนดขอบเขตเป็นแบบคงที่เมื่อเทียบกับการกำหนดขอบเขตแบบไดนามิกที่ใช้ในเชลล์อื่นรวมถึง ksh88):
$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace
ในzsh
นั้นทำด้วยlocaloptions
ตัวเลือก:
$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace
POSIXly คุณสามารถทำ:
case $- in
(*x*) restore=;;
(*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace
อย่างไรก็ตามเชลล์บางตัวจะส่งออก a + 2> /dev/null
ตามการกู้คืน (และคุณจะเห็นร่องรอยของcase
โครงสร้างนั้นถ้าset -x
เปิดใช้งานแล้ว) วิธีการนั้นยังไม่ได้เข้ามาใหม่ (เช่นถ้าคุณทำในฟังก์ชั่นที่เรียกตัวเองหรือฟังก์ชั่นอื่นที่ใช้เคล็ดลับเดียวกัน)
ดูhttps://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh (ขอบเขตโลคัลสำหรับตัวแปรและตัวเลือกสำหรับ POSIX เชลล์) สำหรับวิธีใช้สแต็กที่ทำงานโดยรอบ
ด้วยเชลล์ใด ๆ คุณสามารถใช้ subshells เพื่อ จำกัด ขอบเขตของตัวเลือก
$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace
อย่างไรก็ตามนั่น จำกัด ขอบเขตของทุกสิ่ง (ตัวแปรฟังก์ชั่นนามแฝงการเปลี่ยนเส้นทางไดเรกทอรีการทำงานปัจจุบัน ... ) ไม่ใช่แค่ตัวเลือก
oldstate=$(set +o)
มันเป็นวิธีที่ง่ายกว่า (และ POSIX) ในการจัดเก็บตัวเลือกทั้งหมด
pdksh
/ mksh
(และอนุพันธ์ pdksh อื่น ๆ ) หรือzsh
ที่set +o
จะส่งออกเฉพาะค่าเบี่ยงเบนจากการตั้งค่าเริ่มต้น นั่นจะใช้ได้กับ bash / dash / yash แต่ไม่สามารถพกพาได้
คุณสามารถอ่าน$-
ตัวแปรที่จุดเริ่มต้นเพื่อดูว่า-x
มีการตั้งค่าหรือไม่แล้วบันทึกลงในตัวแปรเช่น
if [[ $- == *x* ]]; then
was_x_set=1
else
was_x_set=0
fi
จากคู่มือ Bash :
($ -, ยัติภังค์.) ขยายเป็นแฟล็กตัวเลือกปัจจุบันตามที่ระบุไว้เมื่อร้องขอโดยคำสั่ง set builtin หรือที่กำหนดโดยเชลล์เอง (เช่นตัวเลือก -i)
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x
ในทุบตี, $ SHELLOPTSถูกตั้งค่าด้วยการตั้งค่าสถานะที่เปิดอยู่ ตรวจสอบก่อนที่คุณจะเปิด xtrace และรีเซ็ต xtrace เฉพาะเมื่อปิดก่อนหน้านี้
เพียงเพื่อระบุความชัดเจนหากset -x
จะมีผลบังคับใช้ในช่วงระยะเวลาของสคริปต์และนี่เป็นเพียงมาตรการทดสอบชั่วคราว (เพื่อไม่ให้เป็นส่วนหนึ่งของผลลัพธ์อย่างถาวร) จากนั้นเรียกใช้สคริปต์ด้วย-x
ตัวเลือกเช่น
$ bash -x path_to_script.sh
... หรือเปลี่ยนสคริปต์ชั่วคราว (บรรทัดแรก) เพื่อเปิดใช้งานการดีบักโดยเพิ่ม-x
ตัวเลือก:
#!/bin/bash -x
...rest of script...
ฉันรู้ว่านี่อาจเป็นจังหวะที่กว้างเกินไปสำหรับสิ่งที่คุณต้องการ แต่มันเป็นวิธีที่ง่ายที่สุดและเร็วที่สุดในการเปิด / ปิดโดยไม่ซับซ้อนเกินไปสคริปต์กับสิ่งชั่วคราวที่คุณอาจต้องการลบต่อไป (ในประสบการณ์ของฉัน)
สิ่งนี้จัดเตรียมฟังก์ชันเพื่อบันทึกและกู้คืนแฟล็กที่มองเห็นได้ผ่าน$-
พารามิเตอร์พิเศษPOSIX เราใช้local
ส่วนขยายสำหรับตัวแปรท้องถิ่น ใน POSIX ที่สอดคล้องกับสคริปต์พกพาตัวแปรทั่วโลกจะถูกนำมาใช้ (ไม่มีlocal
คำหลัก):
save_opts()
{
echo $-
}
restore_opts()
{
local saved=$1
local on
local off=$-
while [ ${#saved} -gt 0 ] ; do
local rest=${saved#?}
local first=${saved%$rest}
if echo $off | grep -q $first ; then
off=$(echo $off | tr -d $first)
fi
on="$on$first"
saved=$rest
done
set ${on+"-$on"} ${off+"+$off"}
}
สิ่งนี้ถูกใช้คล้ายกับวิธีการบันทึกและขัดจังหวะแฟล็กในเคอร์เนล Linux:
Shell: Kernel:
flags=$(save_opts) long flags;
save_flags (flags);
set -x # or any other local_irq_disable(); /* disable irqs on this core */
# ... -x enabled ... /* ... interrupts disabled ... */
restore_opts $flags restore_flags(flags);
# ... x restored ... /* ... interrupts restored ... */
สิ่งนี้จะไม่ทำงานสำหรับตัวเลือกเพิ่มเติมใด ๆ ที่ไม่รวมอยู่ใน$-
ตัวแปร
เพิ่งสังเกตเห็นว่า POSIX มีสิ่งที่ฉันกำลังมองหา: +o
อาร์กิวเมนต์ของset
ไม่ได้เป็นตัวเลือก แต่คำสั่งที่ทิ้งคำสั่งจำนวนมากซึ่งถ้าeval
-ed จะเรียกคืนตัวเลือก ดังนั้น:
flags=$(set +o)
set -x
# ...
eval "$flags"
แค่นั้นแหละ.
ปัญหาเล็ก ๆ อย่างหนึ่งคือถ้า-x
ตัวเลือกถูกเปิดใช้ก่อนหน้านี้จะเห็นคำสั่งที่eval
น่าเกลียดset -o
มากมาย เพื่อกำจัดสิ่งนี้เราสามารถทำสิ่งต่อไปนี้:
set +x # turn off trace not to see the flurry of set -o.
eval "$flags" # restore flags
คุณสามารถใช้เชลล์ย่อย
(
set …
do stuff
)
Other stuff, that set does not apply to