สิ่งสำคัญคือต้องตระหนักว่าจริงๆแล้วมันคือเชลล์ที่ขยายfoo*ไปยังรายการของชื่อไฟล์ที่ตรงกันดังนั้นจึงมีความmvสามารถเล็กน้อยที่จะทำเอง
ปัญหาตรงนี้คือเมื่อ glob ไม่ตรงกันเชลล์บางตัวbash(และเชลล์คล้ายบอร์นอื่น ๆ ส่วนใหญ่พฤติกรรมการบั๊กกี้นั้นถูกนำเสนอโดยบอร์นเชลล์ในช่วงปลายยุค 70) ผ่านรูปแบบคำต่อคำไปยังคำสั่ง
ดังนั้นที่นี่เมื่อfoo*ไม่ตรงกับไฟล์ใด ๆ แทนการยกเลิกคำสั่ง (เช่นก่อนบอร์นเปลือกหอยและเปลือกหอยทันสมัยหลายอย่างทำ) เปลือกผ่านคำต่อคำfoo*ไฟล์mvดังนั้นโดยทั่วไปขอให้ย้ายไฟล์ที่เรียกว่าmvfoo*
ไฟล์นั้นไม่มีอยู่ ถ้าเป็นเช่นนั้นจริง ๆ แล้วมันจะตรงกับรูปแบบดังนั้นmvรายงานข้อผิดพลาด หากรูปแบบได้รับการfoo[xy]แทนที่mvอาจมีการย้ายไฟล์ที่เรียกโดยไม่ได้ตั้งใจfoo[xy]แทนfooxและfooyไฟล์
ตอนนี้แม้ในเชลล์เหล่านั้นที่ไม่มีปัญหา (pre-Bourne, csh, tcsh, ปลา, zsh, bash -O failglob) คุณจะยังคงได้รับข้อผิดพลาดmv foo* ~/barแต่คราวนี้โดยเชลล์
หากคุณต้องการพิจารณาว่าไม่ใช่ข้อผิดพลาดหากไม่มีการจับคู่ไฟล์foo*และในกรณีนั้นไม่ย้ายอะไรคุณจะต้องสร้างรายการไฟล์ก่อน (ในลักษณะที่ไม่ทำให้เกิดข้อผิดพลาดเช่นโดยใช้nullglobตัวเลือกของ เชลล์บางตัว) และจากนั้นเรียกใช้เท่านั้นmvคือรายการไม่ว่างเปล่า
นั่นจะดีกว่าการซ่อนข้อผิดพลาดทั้งหมดของmv(เช่นการเพิ่ม2> /dev/nullจะ) ราวกับว่าmvล้มเหลวด้วยเหตุผลอื่นใดคุณอาจยังคงต้องการที่จะรู้ว่าทำไม
ใน zsh
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
หรือใช้ฟังก์ชันที่ไม่ระบุชื่อเพื่อหลีกเลี่ยงการใช้ตัวแปรชั่วคราว:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zshเป็นหนึ่งในเชลล์เหล่านั้นที่ไม่มีบัก Bourne และรายงานข้อผิดพลาดโดยไม่ต้องดำเนินการคำสั่งเมื่อ glob ไม่ตรงกัน (และnullglobตัวเลือกไม่ได้เปิดใช้งาน) ดังนั้นที่นี่คุณสามารถซ่อนzshข้อผิดพลาดและเรียกคืนได้ stderr ทำmvเช่นนั้นคุณจะยังคงเห็นmvข้อผิดพลาดถ้ามี แต่ไม่ใช่ข้อผิดพลาดเกี่ยวกับ globs ที่ไม่ตรงกัน:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
หรือคุณสามารถใช้zargsซึ่งจะหลีกเลี่ยงปัญหาหากfoo*glob จะขยายเป็นไฟล์คนเกินไป
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
ใน ksh93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
ในทุบตี:
bashไม่มีไวยากรณ์ที่จะเปิดใช้งานnullglobสำหรับหนึ่ง glob เท่านั้นและfailglobตัวเลือกยกเลิกnullglobดังนั้นคุณต้องมีสิ่งต่าง ๆ เช่น:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
หรือตั้งค่าตัวเลือกใน subshell เพื่อบันทึกต้องบันทึกก่อนและเรียกคืนหลังจากนั้น
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
ใน yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
ใน fish
ในเชลล์ปลาพฤติกรรม nullglob เป็นค่าเริ่มต้นสำหรับsetคำสั่งดังนั้นมันเป็นเพียง:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXly
ไม่มีnullglobตัวเลือกใน POSIX shและไม่มีอาร์เรย์อื่นนอกเหนือจากพารามิเตอร์ตำแหน่ง มีเคล็ดลับที่คุณสามารถใช้เพื่อตรวจสอบว่ากลมจับคู่หรือไม่:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
โดยการใช้ทั้ง a foo[*]และfoo*glob เราสามารถแยกความแตกต่างระหว่างเคสที่ไม่มีไฟล์ที่ตรงกันและอีกไฟล์หนึ่งที่มีไฟล์เดียวที่เรียกว่าfoo*(ซึ่งset -- foo*ไม่สามารถทำได้)
อ่านเพิ่มเติม:
mv foo* ~/bar/ 2> /dev/null?