ออกข้อผิดพลาดเมื่อใช้ตัวแปรเชลล์ที่ว่างเปล่า


22

บางครั้งฉันก็ใช้$PROJECT_HOME/*เพื่อลบไฟล์ทั้งหมดในโครงการ เมื่อตัวแปรสภาพแวดล้อมPROJECT_HOMEไม่ได้ถูกตั้งค่า (เพราะฉันทำsuและผู้ใช้ใหม่ไม่มีชุดตัวแปรสภาพแวดล้อมนี้) จึงเริ่มลบไฟล์ทั้งหมดจากโฟลเดอร์รูท นี่คือสันทราย

ฉันbashจะกำหนดค่าให้เกิดข้อผิดพลาดได้อย่างไรเมื่อฉันใช้ตัวแปรสภาพแวดล้อมที่ไม่ได้กำหนดในเชลล์?


5
set -uจะทำในสิ่งที่คุณต้องการ
cuonglm

คุณสามารถทำให้มันเป็นคำตอบได้หรือไม่?

2
แน่นอนคุณจะไม่เริ่มต้น vars ของคุณเป็นสตริงว่าง [ -z "$VAR" ]ทำงานร่วมกับไม่กำหนดค่าเริ่มต้นVARเกินไป การเริ่มต้นเป็นเพียงการแสดงพฤติกรรมที่ไม่พึงประสงค์ - จุดของฉันคือถ้า vars ของคุณเคยเริ่มต้นกับสตริงที่ว่างเปล่าไม่ว่าจะด้วยวิธีใดและคุณทำงานโดยrm -r "$PROJECT_HOME"/*ไม่ได้ตั้งใจset -uคุณจะได้รับพฤติกรรม "สันทราย" IHMO จะปลอดภัยกว่าขออภัยเมื่อต้องปกป้องเนื้อหาทั้งหมดในคอมพิวเตอร์ของคุณ set -uไม่ปลอดภัย
PSkocik

3
"มันยาวมาก"? คุณไม่ควรมองหาวิธีที่สะดวกในการดำเนินการอันตรายด้วยตนเอง คุณควรสร้างฟังก์ชันนามแฝงหรือสคริปต์เพื่อทำสิ่งที่คุณต้องการ ในกรณีนี้การสร้างนามแฝงจากคำสั่งที่แนะนำของ @ PSkocik จะปลอดภัยและสะดวกสบาย
Kyle Strand

1
เกิดอะไรขึ้นถ้าผู้ใช้ตั้งค่าPROJECT_HOME=/etc? เพียงแค่ตรวจสอบค่าว่างไม่เพียงพอที่จะป้องกันความหายนะ คุณไม่ควรใช้ตัวแปรจากผู้ใช้ที่ไม่น่าเชื่อถือเมื่อทำงานเป็นรูท
Barmar

คำตอบ:


27

ใน POSIX เชลล์คุณสามารถใช้set -u :

#!/bin/sh

set -u
: "${UNSET_VAR}"

หรือใช้การขยายพารามิเตอร์ :

: "${UNSET_VAR?Unset variable}"

ในกรณีของคุณคุณควรใช้:?แทน?การล้มเหลวในการตั้งค่า แต่ตัวแปรที่ว่างเปล่า:

rm -rf -- "${PROJECT_HOME:?PROJECT_HOME empty or unset}"/*

17
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*

นอกจากนี้ยังจะจับกรณีที่PROJECT_HOME มีการตั้งค่า แต่ไม่ได้มีอะไร

ตัวอย่าง:

1) สิ่งนี้จะลบทุกอย่างที่คุณสามารถลบได้ในระบบของคุณ (ยกเว้น dotfiles ภายใน/(โดยปกติจะไม่มี)

set -u
PROJECT_HOME=
rm -r "$PROJECT_HOME"/*

2) สิ่งนี้จะไม่ทำอะไรเลย:

PROJECT_HOME=
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/* 

การนำโครงการออกจากบ้านโดยสิ้นเชิงและสร้างใหม่อาจเป็นตัวเลือกอื่น (หากคุณต้องการกำจัด dotfiles ด้วย):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 

1
-zก็โอเค แต่เนื่องจาก$PROJECT_HOMEควรจะเป็นไดเรกทอรีอาจ-dจะดีกว่า [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
kojiro

2
หาก PROJECT_HOME ถูกตั้งค่าเป็น nondirectory นั่นเป็นข้อผิดพลาดที่ไม่รุนแรงซึ่งอาจเกิดจากการพิมพ์ผิด การ-dตรวจสอบจะซ่อนข้อผิดพลาดนั้น ฉันคิดว่ามันจะดีกว่าถ้ามันไปrmและrmบ่นเกี่ยวกับมันออกมาดัง ๆ
PSkocik

2
หากตั้งค่า PROJECT_HOME แต่ชื่อไม่ใช่ไดเรกทอรี[[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"จะไม่ทำอะไรเลยเงียบ ๆ แต่[[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"จะลบ "$ PROJECT_HOME" แบบไม่โต้ตอบแม้ว่าจะเป็นไฟล์ที่ไม่ใช่ไดเรกทอรี การได้รับข้อความแสดงข้อผิดพลาดจะไม่เป็นปัญหา:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
kojiro

1
ตอนนี้ "ตั้งใจ" ตั้งPROJECT_HOME="/."...
Hagen von Eitzen

1
@HagenvonEitzen หาก PROJECT_HOME ถูกตั้งค่าเป็นรูทโพรซีเดอร์ที่ว่าง PROJECT_HOME จะทำให้รูทว่าง นั่นเป็นพฤติกรรมที่คาดหวังและสมเหตุสมผลอย่างสมบูรณ์แบบ และคุณไม่ต้องการแม้แต่จุดสุดท้าย
PSkocik

0

อีกวิธีในการทำสิ่งนี้:

rm -r "${somevar:-/tmp/or_this_if_somevar_is_empty}"/*

มีการแทนที่ตัวแปรหลายตัวหนึ่งตัวด้านบนคือเมื่อ "somevar" ว่างเปล่า (และในกรณีนั้นจะพยายามลบ/tmp/or_this_if_somevar_is_empty/*)


1
หรือ: rm -fr ${ENV_VAR:?suitably caustic message here}/*แต่มันอาจจะยังคงมีมูลค่าการตรวจสอบว่าค่าไม่ได้แผนที่ไปยังไดเรกทอรีรากสังเกตว่ามีหลายวิธีที่จะล้มล้างการทดสอบอย่างง่าย: //, /.., /usr/who/../.....
โจนาธาน Leffler

ใช่. หากคุณกำลังจะใช้การขยายพารามิเตอร์คุณอาจใช้อันที่จริงแล้วเกิดข้อผิดพลาด
Digital Trauma
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.