เป็นวิธีที่ดีที่สุดในการตรวจสอบว่าตัวแปรใน bash ว่างเปล่า ("") คืออะไร?
ฉันเคยได้ยินว่าขอแนะนำให้ฉันทำ if [ "x$variable" = "x" ]
นั่นเป็นวิธีที่ถูกต้องหรือไม่ (ต้องมีสิ่งที่ตรงไปตรงมามากขึ้น)
เป็นวิธีที่ดีที่สุดในการตรวจสอบว่าตัวแปรใน bash ว่างเปล่า ("") คืออะไร?
ฉันเคยได้ยินว่าขอแนะนำให้ฉันทำ if [ "x$variable" = "x" ]
นั่นเป็นวิธีที่ถูกต้องหรือไม่ (ต้องมีสิ่งที่ตรงไปตรงมามากขึ้น)
คำตอบ:
สิ่งนี้จะคืนค่าจริงหากตัวแปรไม่ได้ถูกตั้งค่าหรือตั้งค่าเป็นสตริงว่าง ("")
if [ -z "$VAR" ];
if [ ! -z "$VAR" ];
-z
คือ-n
if [ -n "$VAR" ];
$var
ในบรรทัดคำสั่งจะถูกแยกโดยช่องว่างในรายการของพารามิเตอร์ในขณะที่"$var"
จะเป็นเพียงหนึ่งพารามิเตอร์ การอ้างอิงตัวแปรบ่อยครั้งเป็นวิธีปฏิบัติที่ดีและห้ามไม่ให้คุณสะดุดชื่อไฟล์ที่มีช่องว่าง (เหนือสิ่งอื่นใด) ตัวอย่าง: หลังจากทำa="x --help"
แล้วลองcat $a
- มันจะให้หน้าช่วยเหลือสำหรับcat
คุณ แล้วลองcat "$a"
- มันจะ (ปกติ) cat: x --help: No such file or directory
กล่าวว่า พูดสั้น ๆ ให้พูดเร็วและพูดบ่อย ๆ และคุณแทบจะไม่เสียใจเลย
ใน Bash เมื่อคุณไม่กังวลเกี่ยวกับความสามารถในการพกพาของเชลล์ที่ไม่สนับสนุนคุณควรใช้ไวยากรณ์วงเล็บคู่:
ข้อใดข้อหนึ่งต่อไปนี้:
if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]
ใน Bash โดยใช้เครื่องหมายวงเล็บสองช่องราคาไม่จำเป็น คุณสามารถลดความซับซ้อนของการทดสอบสำหรับตัวแปรที่จะมีค่าไปที่:
if [[ $variable ]]
ไวยากรณ์นี้เข้ากันได้กับ ksh (อย่างน้อย ksh93 อยู่ดี) มันไม่ทำงานใน POSIX บริสุทธิ์หรือเชลล์ Bourne รุ่นเก่าเช่น sh หรือ dash
ดูคำตอบของฉันที่นี่และBashFAQ / 031สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่างระหว่างวงเล็บเหลี่ยมสองชั้นและเดี่ยว
คุณสามารถทดสอบเพื่อดูว่าตัวแปรไม่มีการตั้งค่าเฉพาะ (แตกต่างจากสตริงว่าง):
if [[ -z ${variable+x} ]]
โดยที่ "x" เป็นกฎเกณฑ์
หากคุณต้องการทราบว่าตัวแปรเป็นโมฆะหรือไม่ไม่ได้ตั้งค่า:
if [[ -z $variable && ${variable+x} ]]
if [[ $variable ]]
งานได้ดีสำหรับฉันและไม่ต้องการแม้แต่สิ่งเดียวset -u
ที่ต้องการโดยหนึ่งในโซลูชันที่เสนออื่น ๆ
sh
แทน Bash หากคุณต้องการความสามารถที่เพิ่มขึ้นที่มีให้ใช้ Bash และใช้อย่างเต็มที่
;
ในตอนท้าย then
สามารถจะอยู่ในบรรทัดถัดไปโดยไม่ต้องอัฒภาคที่ทั้งหมด
ตัวแปรใน bash (และเชลล์ที่เข้ากันได้กับ POSIX) สามารถเป็นหนึ่งในสามสถานะ:
เวลาส่วนใหญ่คุณเพียงแค่ต้องรู้ว่าตัวแปรถูกตั้งค่าเป็นสตริงที่ไม่ว่างเปล่าหรือไม่ แต่ในบางครั้งการแยกความแตกต่างระหว่างการตั้งค่าและการตั้งค่าเป็นสตริงว่างนั้นเป็นสิ่งสำคัญ
ต่อไปนี้เป็นตัวอย่างของวิธีที่คุณสามารถทดสอบความเป็นไปได้ที่หลากหลายและใช้งานได้ใน bash หรือเชลล์ที่รองรับ POSIX:
if [ -z "${VAR}" ]; then
echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
echo "VAR is either unset or set to a non-empty string"
fi
นี่คือสิ่งเดียวกัน แต่ในรูปแบบตารางที่มีประโยชน์:
+-------+-------+-----------+
VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ] | true | true | false |
| [ -z "${VAR+set}" ] | true | false | false |
| [ -z "${VAR-unset}" ] | false | true | false |
| [ -n "${VAR}" ] | false | false | true |
| [ -n "${VAR+set}" ] | false | true | true |
| [ -n "${VAR-unset}" ] | true | false | true |
+-----------------------+-------+-------+-----------+
${VAR+foo}
สร้างขยายสตริงที่ว่างเปล่าถ้าVAR
ไม่มีการตั้งค่าหรือfoo
ถ้าVAR
มีการตั้งค่าเพื่ออะไร (รวมทั้งสตริงว่างเปล่า)
${VAR-foo}
สร้างขยายมูลค่าของVAR
ถ้าตั้ง (รวมถึงการตั้งค่าเป็นสตริงว่างเปล่า) และfoo
ถ้าไม่มีการตั้งค่า สิ่งนี้มีประโยชน์สำหรับการจัดเตรียมค่าเริ่มต้นที่ผู้ใช้สามารถข้ามได้ (เช่น${COLOR-red}
บอกว่าจะใช้red
ยกเว้นว่าตัวแปรCOLOR
ถูกตั้งค่าเป็นบางอย่าง)
เหตุผลที่[ x"${VAR}" = x ]
มักแนะนำให้ทำการทดสอบว่าตัวแปรไม่ได้ถูกตั้งค่าหรือตั้งค่าเป็นสตริงว่างเปล่านั้นเป็นเพราะการใช้งานบางส่วนของ[
คำสั่ง (หรือที่รู้จักกันในชื่อtest
) ว่าเป็นรถ หากVAR
ตั้งค่าเป็นบางสิ่ง-n
บางอย่างการใช้งานบางอย่างจะทำสิ่งผิดเมื่อได้รับ[ "${VAR}" = "" ]
เนื่องจากอาร์กิวเมนต์แรกที่[
ตีความผิดพลาดเป็น-n
โอเปอเรเตอร์ไม่ใช่สตริง
[ -z "${VAR-set}" ]
การทดสอบสำหรับการตั้งค่าตัวแปรสตริงที่ว่างเปล่ายังสามารถทำได้โดยใช้
set -u
หรือset -o nounset
ทุบตีการทดสอบจะส่งผลให้เกิดข้อผิดพลาด "bash: VAR: unbound variable" ดูstackoverflow.com/a/13864829สำหรับการตรวจสอบที่เชื่อถือได้ [ -z "${VAR:-}" ]
ฉันไปเพื่อตรวจสอบว่าตัวแปรเป็นโมฆะหรือไม่มีการตั้งค่าเป็น ฉันตรวจสอบว่าตัวแปรไม่ว่างเปล่า[ "${VAR:-}" ]
หรือไม่
-z
เป็นวิธีที่ดีที่สุด
ตัวเลือกอื่นที่ฉันใช้คือตั้งค่าตัวแปร แต่มันสามารถแทนที่ได้โดยตัวแปรอื่นเช่น
export PORT=${MY_PORT:-5432}
หาก$MY_PORT
ตัวแปรว่างเปล่าPORT
จะได้รับการตั้งค่าเป็น 5432 มิฉะนั้น PORT จะถูกตั้งค่าMY_PORT
เป็น หมายเหตุไวยากรณ์รวมถึงเครื่องหมายจุดคู่และเส้นประ
set -o nounset
ในบางสคริปต์
หากคุณสนใจที่จะแยกความแตกต่างของกรณีของ set-empty กับสถานะ unset ให้ดูที่ตัวเลือก -u สำหรับ bash:
$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR
$ [ -z "$BAR" ] && echo true
true
ทางเลือกที่ฉันเคยเห็น[ -z "$foo" ]
มีดังต่อไปนี้ แต่ฉันไม่แน่ใจว่าทำไมผู้คนถึงใช้วิธีนี้ทุกคนรู้
[ "x${foo}" = "x" ]
อย่างไรก็ตามหากคุณไม่อนุญาตให้ใช้ตัวแปรที่ไม่ได้ตั้งค่า (ไม่ว่าจะโดยset -u
หรือset -o nounset
) คุณจะประสบปัญหากับทั้งสองวิธี มีวิธีแก้ไขง่ายๆดังนี้:
[ -z "${foo:-}" ]
หมายเหตุ: สิ่งนี้จะปล่อยให้ตัวแปรยกเลิกการตั้งค่า
-z
ที่pubs.opengroup.org/onlinepubs/009695399/utilities/test.html -z
โดยทั่วไปก็ไม่ได้หมายความว่าจะเป็นทางเลือกที่จะ แต่มันจัดการกรณีที่$foo
สามารถขยายไปยังสิ่งที่เริ่มต้นด้วย metacharacter ที่[
หรือtest
จะสับสนโดย การใส่ตัวอักษรที่ไม่ใช่ตัวอักษรตามอำเภอใจในตอนต้นจะช่วยลดโอกาสที่จะเกิดขึ้น
คำถามถามวิธีการตรวจสอบว่าตัวแปรเป็นสตริงที่ว่างเปล่าและคำตอบที่ดีที่สุดที่จะได้รับอยู่แล้วว่า
แต่ฉันลงจอดที่นี่หลังจากช่วงเวลาหนึ่งผ่านการเขียนโปรแกรมใน php และสิ่งที่ฉันค้นหาจริง ๆ คือการตรวจสอบว่าฟังก์ชั่นที่ว่างเปล่าใน phpทำงานในเชลล์ทุบตี
หลังจากอ่านคำตอบฉันรู้ว่าฉันไม่ได้คิดอย่างถูกต้องในการทุบตี แต่อย่างใดในเวลานั้นฟังก์ชั่นที่ว่างเปล่าใน php จะมีประโยชน์มากในรหัสทุบตีของฉัน
เนื่องจากฉันคิดว่าสิ่งนี้สามารถเกิดขึ้นกับผู้อื่นได้ฉันตัดสินใจที่จะแปลงฟังก์ชัน php empty เป็น bash
ตามคู่มือ php :
ตัวแปรถูกพิจารณาว่าว่างเปล่าหากไม่มีอยู่หรือถ้าค่าเป็นหนึ่งในค่าต่อไปนี้:
แน่นอนกรณีที่เป็นโมฆะและเท็จไม่สามารถแปลงเป็น bash ดังนั้นพวกเขาจะถูกละเว้น
function empty
{
local var="$1"
# Return true if:
# 1. var is a null string ("" as empty string)
# 2. a non set variable is passed
# 3. a declared variable or array but without a value is passed
# 4. an empty array is passed
if test -z "$var"
then
[[ $( echo "1" ) ]]
return
# Return true if var is zero (0 as an integer or "0" as a string)
elif [ "$var" == 0 2> /dev/null ]
then
[[ $( echo "1" ) ]]
return
# Return true if var is 0.0 (0 as a float)
elif [ "$var" == 0.0 2> /dev/null ]
then
[[ $( echo "1" ) ]]
return
fi
[[ $( echo "" ) ]]
}
ตัวอย่างการใช้งาน:
if empty "${var}"
then
echo "empty"
else
echo "not empty"
fi
การสาธิต:
ตัวอย่างต่อไปนี้:
#!/bin/bash
vars=(
""
0
0.0
"0"
1
"string"
" "
)
for (( i=0; i<${#vars[@]}; i++ ))
do
var="${vars[$i]}"
if empty "${var}"
then
what="empty"
else
what="not empty"
fi
echo "VAR \"$var\" is $what"
done
exit
เอาท์พุท:
VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty
ต้องบอกว่าในตรรกะทุบตีการตรวจสอบในศูนย์ในฟังก์ชั่นนี้อาจทำให้เกิดปัญหาข้างเคียงทุกคนที่ใช้ฟังก์ชั่นนี้ควรประเมินความเสี่ยงนี้และอาจตัดสินใจที่จะตัดเช็คเหล่านั้นออกจากคนแรกเท่านั้น
empty
- ทำไมคุณถึงเขียน[[ $( echo "1" ) ]] ; return
แทนที่จะเรียบง่ายreturn 1
?
if-then และ -z ทั้งหมดนั้นไม่จำเป็น
["$ foo"] && echo "foo ไม่ว่าง" ["$ foo"] || echo "foo is empty"
สิ่งนี้เป็นจริงทุกอย่างเมื่อตั้งค่า $ FOO และไม่มีค่า:
[ "${FOO+x}" = x ] && [ -z "$FOO" ]
ส่วนตัวชอบวิธีที่ชัดเจนมากขึ้นในการตรวจสอบ:
if [ "${VARIABLE}" == "" ]; then
echo VARIABLE is empty
else
echo VARIABLE is not empty
fi
ส่วนขยาย oneliner ของโซลูชันของduffbeer703 :
#! /bin/bash
[ -z "$1" ] || some_command_that_needs_$1_parameter
5 เซนต์ของฉัน: นอกจากนี้ยังมีไวยากรณ์ที่สั้นกว่าif ...
อันนี้:
VALUE="${1?"Usage: $0 value"}"
บรรทัดนี้จะตั้งค่า VALUE หากมีการระบุอาร์กิวเมนต์และจะพิมพ์ข้อความแสดงข้อผิดพลาดที่เตรียมไว้พร้อมกับหมายเลขบรรทัดสคริปต์ในกรณีที่เกิดข้อผิดพลาด (และจะยุติการเรียกใช้สคริปต์)
อีกตัวอย่างหนึ่งสามารถพบได้ในabs-guide (ค้นหา«ตัวอย่างที่ 10-7 »)
ไม่ใช่คำตอบที่แน่นอน แต่พบกับเคล็ดลับนี้ หากสตริงที่คุณต้องการมาจาก "คำสั่ง" คุณสามารถจัดเก็บคำสั่งใน env ได้ ตัวแปรแล้วดำเนินการทุกครั้งสำหรับคำสั่ง if แล้วไม่จำเป็นต้องใช้วงเล็บ!
ตัวอย่างเช่นคำสั่งนี้ซึ่งกำหนดว่าคุณเป็นเดเบียนหรือไม่:
grep debian /proc/version
ตัวอย่างเต็มรูปแบบ:
IS_DEBIAN="grep -i debian /proc/version"
if $IS_DEBIAN; then
echo 'yes debian'
else
echo 'non debian'
fi
ดังนั้นนี่เป็นวิธีการทางอ้อม (เรียกใช้ซ้ำทุกครั้ง) เพื่อตรวจสอบสตริงว่างเปล่า (มันเกิดขึ้นเพื่อตรวจสอบการตอบสนองข้อผิดพลาดจากคำสั่ง