ให้คุณมีสิทธิ์ในการดำเนินการไดเรกทอรีปัจจุบัน - หรือในไดเรกทอรีที่คุณดำเนินการเชลล์สคริปต์ของคุณ - cd
ถ้าคุณต้องการเส้นทางที่แน่นอนไปยังไดเรกทอรีทั้งหมดที่คุณต้องการ
ขั้นตอนที่ 10 ของcd
ข้อมูลจำเพาะ
ถ้า-P
ตัวเลือกอยู่ในผลกระทบที่ตัวแปรสภาพแวดล้อมจะถูกกำหนดให้เป็นสตริงที่จะถูกส่งออกโดย$PWD
pwd -P
หากมีการอนุญาตไม่เพียงพอในไดเร็กทอรีใหม่หรือบนพาเรนต์ใด ๆ ของไดเร็กทอรีนั้นเพื่อกำหนดไดเร็กทอรีการทำงานปัจจุบันค่าของ$PWD
ตัวแปรสภาวะแวดล้อมจะไม่ถูกระบุ
และบน pwd -P
ชื่อพา ธ ที่เขียนไปยังเอาต์พุตมาตรฐานจะต้องไม่มีส่วนประกอบใด ๆ ที่อ้างถึงไฟล์ของลิงค์สัญลักษณ์ประเภท หากมีหลายชื่อพา ธ ที่pwd
ยูทิลิตีสามารถเขียนไปยังเอาต์พุตมาตรฐานได้เริ่มต้นหนึ่งด้วยอักขระเดี่ยว / สแลชและอย่างน้อยหนึ่งเริ่มต้นด้วยอักขระสอง / สแลชแล้วมันจะเขียนชื่อพา ธ เริ่มต้นด้วยอักขระเดียว / เครื่องหมายทับ ชื่อพา ธ จะต้องไม่มีอักขระที่ไม่จำเป็น / สแลชหลังจากอักขระหนึ่งหรือสอง / สแลชนำหน้า
เป็นเพราะcd -P
มีการตั้งค่าไดเรกทอรีการทำงานปัจจุบันเป็นสิ่งที่pwd -P
ควรพิมพ์และที่cd -
จะพิมพ์$OLDPWD
งานดังต่อไปนี้:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
เอาท์พุท
/home/mikeserv/test/ln
รอมันอยู่...
cd -P . ; cd . ; cd -
เอาท์พุท
/home/mikeserv/test/dir
และเมื่อฉันพิมพ์ฉันพิมพ์cd -
กำหนดทันทีที่ฉันเป็นเส้นทางที่แน่นอนไป- ดังนั้นฉันไม่ต้องการตัวแปรอื่น ๆ และอันที่จริงฉันควรจะไม่จำเป็นต้องต่อท้ายแต่มีพฤติกรรมที่ระบุการตั้งค่าไปในเปลือกโต้ตอบเมื่อ เป็นตกแต่ง ดังนั้นมันจึงเป็นเพียงนิสัยที่ดีในการพัฒนา$OLDPWD
cd
$PWD
cd -P .
$PWD
/
.
$PWD
$HOME
cd
ดังนั้นเพียงทำตามข้างบนเส้นทาง${0%/*}
ควรมากกว่าเพียงพอที่จะตรวจสอบ$0
เส้นทางของ แต่ในกรณีที่$0
ตัวเองเป็น soft-link คุณอาจไม่สามารถเปลี่ยนไดเรกทอรีเป็นโชคไม่ดี
นี่คือฟังก์ชั่นที่จะจัดการกับสิ่งนั้น:
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
มันพยายามทำมากที่สุดเท่าที่จะทำได้ในเชลล์ปัจจุบัน - โดยไม่ต้องเรียกใช้ subshell - แม้ว่าจะมี subshells ที่เรียกใช้สำหรับข้อผิดพลาดและซอฟต์ลิงก์ที่ไม่ได้ชี้ไปที่ไดเรกทอรี มันขึ้นอยู่กับเปลือกที่เข้ากันได้กับ POSIX และ POSIX ที่เข้ากันได้ls
เช่นเดียวกับ_function()
เนมสเปซที่สะอาด มันจะยังคงทำงานได้ดีโดยไม่ต้องใช้หลังแม้ว่ามันอาจจะเขียนทับunset
ฟังก์ชันเชลล์ปัจจุบันบางส่วนในกรณีนั้น โดยทั่วไปแล้วการพึ่งพาเหล่านี้ทั้งหมดควรมีความน่าเชื่อถืออยู่ในเครื่อง Unix
เรียกว่ามีหรือไม่มีข้อโต้แย้งสิ่งแรกที่มันจะถูกรีเซ็ตเป็นค่า$PWD
มาตรฐานของมัน - มันแก้ไขลิงก์ใด ๆ ในนั้นไปยังเป้าหมายของพวกเขาตามความจำเป็น เรียกว่าไม่มีข้อโต้แย้งและที่เกี่ยวกับมัน แต่เรียกกับพวกเขาและมันจะแก้ไขและกำหนดเป็นที่ยอมรับเส้นทางสำหรับแต่ละหรืออื่นพิมพ์ข้อความไปstderr
ทำไม
เพราะส่วนใหญ่ทำงานในเชลล์ปัจจุบันมันควรจะสามารถจัดการกับรายการอาร์กิวเมนต์ของความยาวใด ๆ นอกจากนี้ยังมองหา$_zdlm
ตัวแปร(ซึ่งเป็นunset
s เมื่อมันผ่าน)และพิมพ์ค่า C-escaped ทันทีทางด้านขวาของแต่ละอาร์กิวเมนต์ของมันซึ่งแต่ละครั้งจะถูกตามด้วย\n
อักขระ ewline เดียวเสมอ
มันเปลี่ยนแปลงไดเรกทอรีจำนวนมาก แต่นอกเหนือจากการตั้งค่าเป็นค่ามาตรฐานของมันจะไม่ส่งผลกระทบ$PWD
ถึงแม้ว่า$OLDPWD
จะไม่สามารถนับได้เมื่อมันผ่าน
มันพยายามที่จะออกจากการขัดแย้งแต่ละครั้งโดยเร็วที่สุด มันพยายามครั้งแรกที่จะเข้ามาcd
ถ้ามันจะสามารถพิมพ์เส้นทางที่ยอมรับข้อโต้แย้งที่จะ$1
stdout
หากไม่สามารถตรวจสอบได้ว่า$1
มีอยู่และไม่ใช่ลิงค์ซอฟต์ หากเป็นจริงจะพิมพ์ออกมา
ด้วยวิธีนี้จะจัดการกับอาร์กิวเมนต์ประเภทไฟล์ใด ๆ ที่เชลล์มีสิทธิ์ที่จะอยู่เว้นแต่$1
จะเป็นลิงค์สัญลักษณ์ที่ไม่ได้ชี้ไปที่ไดเรกทอรี ในกรณีนั้นมันจะเรียกwhile
loop ใน subshell
มันโทรls
ไปอ่านลิงค์ ไดเร็กทอรีปัจจุบันจะต้องเปลี่ยนเป็นค่าเริ่มต้นก่อนเพื่อให้สามารถจัดการพา ธ อ้างอิงใด ๆ ได้อย่างน่าเชื่อถือดังนั้นใน subshell การทดแทนคำสั่งฟังก์ชันจะทำหน้าที่:
cd -...ls...echo /
มันแถบจากด้านซ้ายของls
's ->
ผลผลิตน้อยที่สุดเท่าที่มันจะต้องมีชื่ออย่างเต็มที่การเชื่อมโยงและสตริง ในขณะที่ฉันพยายามหลีกเลี่ยงการทำเช่นนี้ในตอนแรกshift
และ$IFS
ปรากฎว่านี่เป็นวิธีการที่เชื่อถือได้มากที่สุดเท่าที่จะทำได้ นี่เป็นสิ่งเดียวกับที่poor_mans_readlinkของ Gilles ทำและทำได้ดีมาก
มันจะทำซ้ำขั้นตอนนี้ในลูปจนกว่าชื่อไฟล์ที่ส่งคืนมาจากls
ลิงก์ไม่ใช่ซอฟต์ลิงก์แน่นอน ณ จุดนั้นมันเป็นที่ยอมรับเส้นทางที่เป็นมาก่อนด้วยcd
แล้วพิมพ์
ตัวอย่างการใช้งาน:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
เอาท์พุท
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
หรืออาจจะ ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
เอาท์พุท
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...