เส้นทางอาคารแข็งแรง


16

ว่าฉันมีตัวแปรหลายตัวในเชลล์สคริปต์ (เช่นใน zsh):

FOLDER_1, FOLDER_2, etc.

/ตัวแปรเหล่านี้หมายถึงโฟลเดอร์ลงมาจาก ตัวอย่างเช่นถ้าฉันมีเส้นทาง/home/me/stuff/items

ตัวแปรจะเป็น:

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

ตอนนี้พูดว่าฉันต้องการที่จะสร้างเส้นทางที่สอดคล้องกันกลับมาโดยการเชื่อมโยงตัวแปร วิธีหนึ่งที่เป็นไปได้คือการสร้างเส้นทางดังนี้:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

อย่างไรก็ตามบอกว่าตัวแปรบางตัวFOLDER_iมาพร้อมกับเครื่องหมายสแลชข้างหน้าในขณะที่คนอื่นไม่ทราบ (และเราไม่รู้ว่า)

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

คำถามของฉันคือ: ฉันจะสร้างเส้นทางที่แข็งแกร่งได้อย่างไร (เช่นหลีกเลี่ยงการทับสองครั้งและเพิ่มในที่ที่จำเป็น)

ฉันคิดว่าวิธีหนึ่งในการทำเช่นนี้คือการเพิ่ม/ตัวแปรระหว่างคู่เสมอจากนั้นลบรายการที่ซ้ำกันด้วยsedแต่ฉันไม่สามารถทำงานได้ (ฉันไม่แน่ใจว่าฉันจัดการ/อย่างถูกต้องหรือไม่sed)

นอกจากนี้ฉันจะสร้างล้อใหม่ได้หรือไม่ (เช่นมีในตัวที่ทำเช่นนี้แล้ว?)

ในที่สุดถ้าตัวแปรอยู่ในอาร์เรย์เช่นFOLDERSมันเป็นไปได้ไหมที่จะทำโดยไม่ต้องวนซ้ำ? (หรืออีกวิธีหนึ่งโดยการวนซ้ำ แต่ไม่ทราบว่าFOLDERSมีจำนวนเท่าใดในอาเรย์)

คำตอบ:


12

คุณสามารถใช้printfกับอาเรย์:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

ประกอบการจดจ้องสตริงต่อท้ายในกรณีนี้% /โดยการใช้มันจะparts[@]ตัดแต่งสมาชิกแต่ละอาร์เรย์แยกต่างหาก

กุญแจสำคัญในการทำความเข้าใจprintfเคล็ดลับนี้มาจากman 1 printf: "สตริงรูปแบบถูกนำมาใช้ซ้ำได้บ่อยเท่าที่จำเป็นเพื่อให้เป็นไปตามข้อโต้แย้ง"


%วิธีการเดียวใช้งานได้กับเครื่องหมายสแลชเดี่ยวที่กล่าวถึงในภารกิจ เพื่อรองรับเมื่อมีหลายสแลช${parts[@]%%/*}ทำงาน นี่คือลิงค์ไปยังข้อมูลเพิ่มเติมอีกเล็กน้อยเกี่ยวกับปัญหาการทับ: ทับสองหมายความว่าในเส้นทาง UNIX? Is 'cd dir / subdir // ใช้ได้ ...
Peter.O

2
@fered: /*ในกรณีนี้ไม่ได้หมายถึงเครื่องหมายทับหรือมากกว่าแต่เป็นเครื่องหมายทับตามด้วยอักขระจำนวนเท่าใดก็ได้ นั่นหมายความว่าถ้าเส้นทางของคุณเริ่มต้นด้วยเครื่องหมายทับผลลัพธ์จะเป็นสตริงว่าง!
l0b0

ฉันได้พิจารณาตามตัวอย่างแล้วว่าจะมีเพียงเครื่องหมายทับเท่านั้น อย่างไรก็ตามเพื่อปรับให้เข้ากับความเป็นไปได้ของ slash (es), bash's extglob(with regex) สามารถใช้ได้ .. shopt -s extglob; ${parts[@]%%/+(/)}...
Peter.O

15

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

ในการเข้าร่วมองค์ประกอบมากมายใน zsh, คุณสามารถใช้ธงขยายตัวพารามิเตอร์j

dir=${(j:/:)FOLDERS}

คุณสามารถบีบทับเครื่องหมายสแลชซ้ำซ้อนในขณะที่คุณกำลังทำอยู่ แต่นั่นเป็นเครื่องสำอางแท้ๆ

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

ใน ksh และ bash คุณสามารถเข้าร่วมอาร์เรย์โดยใช้อักขระตัวแรกของ$IFSเป็นตัวคั่น จากนั้นคุณสามารถบีบทับเครื่องหมายสแลชซ้ำ ใน bash คุณจะต้องทำshopt -s extglobเพื่อเปิดใช้ ksh globs ในบรรทัดสุดท้ายของตัวอย่างด้านล่าง

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}


1

bash 4แนะนำการขยายแบบวงกลมซึ่งช่วยให้การจับคู่นิพจน์ปกติในการทดแทนพารามิเตอร์${var....}... มันถูกปิดโดยปริยาย เพื่อเปิดใช้งานสคริปต์ของคุณเพียงแค่ตั้งค่าตัวเลือกเปลือกextglob ...

สมมติว่า$ dir ==/home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

ผลลัพธ์ที่ได้คือ$ dir

/home/me/stuff/items  

นี่คือตัวอย่างของ Do-s and-Don't-s - Bash Extended Globbing

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