bash: ปัญหาบางอย่างเมื่อใช้การอ่าน <<<“ $ VARIABLE” บนพาร์ติชันรูทแบบอ่านอย่างเดียว การแก้ไขปัญหาใด ๆ ที่รู้จักกัน?


11

โดยบังเอิญฉันต้องใช้สคริปต์ ATA-ID-to-device-name (อยู่ที่นี่: /server/244944/linux-ata-errors-translating-to-a-device-name/ 426561 # 426561 ) ในพาร์ติชันแบบอ่านอย่างเดียว /ในกรณีที่คุณอยากรู้อยากเห็นมันเป็นคอนโซลการกู้คืนของ Ubuntu ซึ่งจะช่วยให้คุณเข้าถึง/พาร์ติชันของคุณแต่จะติดตั้งเป็นอ่านอย่างเดียวโดยค่าเริ่มต้น ฉันดีใจที่เป็นเช่นนั้นเพราะไม่เช่นนั้นฉันอาจไม่เคยพบว่าสคริปต์ของฉันทำงานผิดปกติในระบบ R / O เนื่องจากบรรทัดที่เฉพาะเจาะจงอันนี้:

IFS=: read HostMain HostMid HostSub <<< "$HostFull"

วิธีนี้ใช้ไม่ได้หากไม่มีสิทธิ์ในการเขียน ฉันไม่คิดเลยว่ามันจะล้มเหลว แต่เห็นได้ชัดว่า<<<ผู้ประกอบการไม่จำเป็นต้องเขียนไฟล์ชั่วคราวบางส่วนไปยังที่อื่น

แต่มีวิธีใดที่จะหลีกเลี่ยงการสร้างไฟล์ชั่วคราวหรือมีวิธีใดที่จะระบุตำแหน่งของไฟล์ที่ถูกเขียนไป? ในคอนโซลการกู้คืนของอูบุนตูมี - ผิดปกติพอ --- เขียนสิทธิ์ใน/runไดเรกทอรีดังนั้นถ้าฉันสามารถ "บอก" readเพื่อเขียนไฟล์ชั่วคราวไปที่อื่นที่ไม่ใช่ปกติ


2
@gniourf_gniourf ไม่“ การเปิดไฟล์อธิบาย” จะไม่เป็นปัญหา (ทำไมจะเป็นเช่นนั้น) และ/dev/fdไม่มีอะไรเกี่ยวข้องกับสิ่งนี้ <<<เป็นผู้กระทำความผิดเพราะมันสร้างไฟล์ชั่วคราว (ซึ่งจะต้องมีการเขียนที่ไหนสักแห่ง)
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

คำตอบ:


8

อาร์เรย์สามารถทำให้การแยกสตริงโดยไม่จำเป็นต้องใช้ไฟล์ชั่วคราว อย่าลืมปิด globbing

set -f
IFS=: Hosts=($HostFull)
HostMain=${Hosts[0]}
HostMid=${Hosts[1]}
HostSub=${Hosts[2]}
set +f

2
หรือแม้จะไม่ได้IFSถ้าคุณกำลังตรวจสอบว่ามีช่องว่างในไม่เป็นดังนั้น:$HostFull Hosts=( ${HostFull//:/ } )หรือแม้ว่าจะมีช่องว่าง: HostMain=${HostFull%%:*}; HostMid=${HostFull#*:}; HostSub=${HostMid#*:}; HostMid=${HostMid%:*}(หรือสิ่งที่คล้ายกันฉันสับสน:D)
gniourf_gniourf

คุณพูดถูกในขณะที่คุณแสดงการขยายตัวของพารามิเตอร์นั้นเป็นเรื่องยุ่งยาก ...
xae

4

ฉันเห็นด้วยกับ @gniourf_gniourf คุณอาจต้องการสิทธิ์เข้าถึงเพื่อเขียน แต่ไม่ใช่ตัวให้คำอธิบายไฟล์น่าจะเป็นไฟล์มากที่สุด

คุณสามารถทดสอบสิ่งนี้ได้โดยติดตามการประมวลผลคำสั่งของคุณเมื่ออยู่ในพาร์ติชันแบบอ่านอย่างเดียว

{ strace -p "$$" & sleep 1; read var1 <<< "hi"; sleep 1; kill "$1"; }

ข้างต้นจะทำงานstraceบนเปลือก Bash (กระบวนการ$$) จากนั้นจะนอนเป็นเวลา 1 วินาทีจากนั้นวิ่งreadจาก HERE STRING ฉันใส่สายอักขระ"hi"ในตำแหน่งนี้ จากนั้นผมก็sleepอีกหนึ่งสองแล้วkillstrace

ตัวอย่าง

ขณะแยกวิเคราะห์ผลลัพธ์นี้คุณจะสังเกตเห็นว่าไฟล์ถูกเปิดเป็นไฟล์O_WRONLYซึ่งใช้สำหรับการเขียนไปยังไฟล์

open("/tmp/sh-thd-4137571604", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600) = 3

ด้านบนเราสามารถเห็นไฟล์ที่ถูกเขียนไปตามลำดับคำสั่งของคุณ


1
ไม่ต้อง“ สร้างไฟล์อธิบาย” (ที่ไม่สมเหตุสมผล) เพื่อสร้างไฟล์ ไม่ใช่readว่าจะเปิดไฟล์สำหรับเขียน (มันอาจจะโง่) แต่มันก็เป็น<<<เช่นนั้น
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

@Gilles - ขอบคุณฉันไม่เข้าใจสิ่งที่บอกฉัน ทำความสะอาด A.
slm

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

3

ฉันพบว่าพารามิเตอร์ตำแหน่งมีประโยชน์มากสำหรับงานประเภทนี้ โดยทั่วไปจะพกพาไปยังทุกเชลล์ได้เช่นกันและไม่มีค่าใช้จ่ายใด ๆ กับไฟล์ชั่วคราว

$ HostFull=main:mid:sub    
$ oldIFS=$IFS; IFS=:; set -- $HostFull; IFS=$oldIFS
$ echo $1
main
$ echo $2
mid
$ echo $3
sub

แนวทางที่ดี! ขอขอบคุณ. นอกจากนี้ฉันชอบที่มันไม่จำเป็นต้องใช้เครื่องมือภายนอกใด ๆ (โดยปกติเราจะไม่ถูกคาดหวังให้พบในสภาพแวดล้อมที่ จำกัด เหล่านั้น แต่อย่างใด) สิ่งเดียวที่อาจทำให้เกิดปัญหาบางอย่างคือ$1, $2, $3สิ่ง: จำได้ว่าในบทนี้มักจะยืนอาร์กิวเมนต์ส่งผ่านไปยังสคริปต์เอง - และในขณะที่เราอยู่ที่: ถ้า IFS หมายถึงเป็นช่องว่าง * IFS = * จะไม่ทำในไวยากรณ์นี้ คุณจะต้องระบุIFS = ''อย่างชัดเจน
ไวยากรณ์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.