คำเตือน:ด้วยวิธีการใด ๆ เหล่านี้คุณต้องระวังว่าคุณกำลังไว้วางใจในความถูกต้องของไฟล์ข้อมูลเพื่อความปลอดภัยเนื่องจากพวกเขาจะถูกเรียกใช้งานเป็นรหัสเชลล์ในสคริปต์ของคุณ การรักษาความปลอดภัยเป็นสิ่งสำคัญยิ่งสำหรับความปลอดภัยของสคริปต์ของคุณ!
การใช้งานอินไลน์อย่างง่ายสำหรับการทำให้เป็นอนุกรมอย่างน้อยหนึ่งตัวแปร
ใช่ทั้ง bash และ zsh คุณสามารถทำให้เนื้อหาของตัวแปรเป็นแบบที่ง่ายต่อการดึงข้อมูลโดยใช้typeset
builtin และ-p
อาร์กิวเมนต์ รูปแบบผลลัพธ์เป็นเช่นนั้นคุณสามารถsource
ส่งออกเพื่อรับสิ่งของของคุณกลับมา
# You have variable(s) $FOO and $BAR already with your stuff
typeset -p FOO BAR > ./serialized_data.sh
คุณสามารถนำข้อมูลของคุณกลับมาเช่นนี้ไม่ว่าจะในภายหลังในสคริปต์ของคุณหรือในสคริปต์อื่นทั้งหมด:
# Load up the serialized data back into the current shell
source serialized_data.sh
สิ่งนี้จะใช้ได้กับ bash, zsh และ ksh รวมถึงการส่งผ่านข้อมูลระหว่างเชลล์ที่แตกต่างกัน Bash จะแปลสิ่งนี้เป็นdeclare
ฟังก์ชั่นbuiltin ในขณะที่ zsh จะดำเนินการนี้ด้วยtypeset
แต่เนื่องจาก bash มีนามแฝงสำหรับสิ่งนี้ที่จะทำงานในแบบที่เราใช้typeset
ที่นี่เพื่อความเข้ากันได้ของ ksh
การใช้งานทั่วไปที่ซับซ้อนยิ่งขึ้น
การใช้งานด้านบนนั้นง่ายมาก แต่ถ้าคุณเรียกมันบ่อยครั้งคุณอาจต้องการให้ฟังก์ชั่นยูทิลิตี้เพื่อให้ง่ายขึ้น นอกจากนี้หากคุณเคยลองใส่ฟังก์ชั่นที่กำหนดเองข้างต้นคุณจะพบกับปัญหาเกี่ยวกับการกำหนดขอบเขตตัวแปร รุ่นนี้ควรกำจัดปัญหาเหล่านั้น
หมายเหตุสำหรับสิ่งเหล่านี้เพื่อรักษาความเข้ากันได้ข้าม bash / zsh เราจะทำการแก้ไขทั้งกรณีtypeset
และdeclare
ดังนั้นรหัสควรทำงานในเปลือกอย่างใดอย่างหนึ่งหรือทั้งสอง นี่เป็นการเพิ่มจำนวนมากและความยุ่งเหยิงที่สามารถกำจัดได้หากคุณทำสิ่งนี้กับเปลือกหอยอันใดอันหนึ่งเท่านั้น
ปัญหาหลักของการใช้ฟังก์ชั่นนี้ (หรือรวมถึงรหัสในฟังก์ชั่นอื่น ๆ ) คือtypeset
ฟังก์ชั่นสร้างรหัสที่เมื่อแหล่งที่มากลับเข้าไปในสคริปต์จากภายในฟังก์ชั่นเริ่มต้นในการสร้างตัวแปรท้องถิ่นมากกว่าตัวแปรทั่วโลก
สามารถแก้ไขได้ด้วยหนึ่งในหลาย ๆ แฮ็ก ความพยายามเริ่มต้นของฉันในการแก้ไขปัญหานี้คือการแยกวิเคราะห์ผลลัพธ์ของกระบวนการซีเรียลไลซ์sed
เพื่อเพิ่มการ-g
ตั้งค่าสถานะเพื่อให้รหัสที่สร้างขึ้นกำหนดตัวแปรทั่วโลกเมื่อแหล่งที่มากลับมา
serialize() {
typeset -p "$1" | sed -E '0,/^(typeset|declare)/{s/ / -g /}' > "./serialized_$1.sh"
}
deserialize() {
source "./serialized_$1.sh"
}
โปรดทราบว่าsed
นิพจน์ที่ขี้ขลาดนั้นจะตรงกับเหตุการณ์แรกของ 'เรียงพิมพ์' หรือ 'ประกาศ' เท่านั้นและเพิ่ม-g
เป็นอาร์กิวเมนต์แรก มีความจำเป็นต้องจับคู่เหตุการณ์แรกเท่านั้นเนื่องจากStéphane Chazelasชี้ให้เห็นอย่างถูกต้องในความคิดเห็นมิฉะนั้นจะจับคู่กรณีที่สตริงที่ต่อเนื่องนั้นมีบรรทัดใหม่ตามตัวอักษรตามด้วยคำที่ประกาศหรือเรียงพิมพ์
นอกเหนือจากการแก้ไข pasing faux pasเบื้องต้นของฉันแล้วStéphaneยังแนะนำวิธีที่ง่ายกว่าในการแฮ็คสิ่งนี้ไม่เพียง แต่ทำตามขั้นตอนด้านปัญหาของการวิเคราะห์สตริง แต่อาจเป็นตะขอที่มีประโยชน์ในการเพิ่มฟังก์ชันการทำงานเพิ่มเติมโดยใช้ฟังก์ชัน wrapper ดำเนินการเมื่อมีการจัดหาข้อมูลกลับมาสิ่งนี้ถือว่าคุณไม่ได้เล่นเกมอื่น ๆ ที่มีคำสั่งประกาศหรือเรียงพิมพ์ แต่เทคนิคนี้จะง่ายต่อการใช้งานในสถานการณ์ที่คุณรวมฟังก์ชั่นนี้เป็นส่วนหนึ่งของฟังก์ชันอื่นของคุณเองหรือ คุณไม่ได้อยู่ในการควบคุมข้อมูลที่กำลังเขียนและมีการ-g
เพิ่มค่าสถานะหรือไม่ สิ่งที่คล้ายกันสามารถทำได้ด้วยนามแฝงดูคำตอบของ Gillesสำหรับการดำเนินการ
เพื่อให้ผลลัพธ์มีประโยชน์มากขึ้นเราสามารถทำซ้ำหลาย ๆ ตัวแปรที่ส่งผ่านไปยังฟังก์ชันของเราโดยสมมติว่าแต่ละคำในอาเรย์อาร์กิวเมนต์เป็นชื่อตัวแปร ผลลัพธ์จะเป็นดังนี้:
serialize() {
for var in $@; do
typeset -p "$var" > "./serialized_$var.sh"
done
}
deserialize() {
declare() { builtin declare -g "$@"; }
typeset() { builtin typeset -g "$@"; }
for var in $@; do
source "./serialized_$var.sh"
done
unset -f declare typeset
}
ด้วยวิธีใดวิธีการใช้งานจะเป็นดังนี้:
# Load some test data into variables
FOO=(an array or something)
BAR=$(uptime)
# Save it out to our serialized data files
serialize FOO BAR
# For testing purposes unset the variables to we know if it worked
unset FOO BAR
# Load the data back in from out data files
deserialize FOO BAR
echo "FOO: $FOO\nBAR: $BAR"