วิธีการหลีกเลี่ยงอักขระพิเศษในสตริงได้อย่างไร


16

สมมติว่า$fileเก็บค่าชื่อไฟล์Dr' A.tifไว้ ในการเขียนโปรแกรม bash ฉันจะหนีจากเครื่องหมายคำพูดเดี่ยวและอักขระพิเศษอื่น ๆ$fileโดยไม่ลบอักขระพิเศษได้อย่างไร

อัพเดทเมื่อวันที่ 9 กรกฎาคม 2557

ตามคำขอจาก @Gillesโค้ดต่อไปนี้ที่ไม่สามารถจัดการได้Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
do
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

หลังจากที่ฉันได้ลองคำตอบจาก @Patrickบนline 1ดูเหมือนว่าจะทำงานให้ฉัน แต่ถ้าผมมีไฟล์เช่นDr\^s A.tif, คำสั่งไม่ได้ดูเหมือนความช่วยเหลือมันแสดงให้เห็นฉันprintf Dr\^s\ A.tifหากฉันลองบนคอนโซลด้วยตนเองเช่นนี้:

printf "%q" "Dr\^s A.tif"

ฉันจะได้ผลลัพธ์นี้:

Dr\\\^s\ A.tif

มีความคิดวิธีจัดการกับเรื่องนี้อย่างไร?


3
คุณคาดหวังว่าจะใช้ $ file ในบริบทใด หรือปัญหานี้กำหนดสตริงที่มีอักขระพิเศษให้กับไฟล์ $ หรือไม่?
ปล้น

ที่จริงคำสั่ง find คืนอาร์เรย์ของรายการไฟล์ให้ฉัน จากนั้นฉันวนรอบรายการไฟล์นี้ไปยังตัวแปร $
huahsin68

2
คุณได้รับคำตอบที่ถูกต้องที่นี่ แต่อาจไม่ใช่คำตอบสำหรับคำถามที่คุณถามจริงๆ จากความคิดเห็นของคุณที่นี่ฉันสงสัยอย่างยิ่งว่าคุณกำลังติดตามผิด เราไม่สามารถช่วยคุณได้มากนักเนื่องจากคุณไม่แสดงรหัสของคุณ อย่างไรก็ตามฉันแนะนำให้คุณอ่านทำไมเชลล์สคริปต์ถึงสำลักช่องว่างหรืออักขระพิเศษอื่น ๆ เป็นพื้นหลัง แสดงสคริปต์ของคุณและอธิบายสิ่งที่คุณต้องการจะทำ
Gilles 'หยุดความชั่วร้าย'

คำตอบ:


14

คุณสามารถใช้printfbuiltin ด้วย%qเพื่อทำสิ่งนี้ให้สำเร็จ ตัวอย่างเช่น:

$ file="Dr' A.tif"
$ printf '%q\n' "$file"
Dr\'\ A.tif

$ file=' foo$bar\baz`'
$ printf '%q\n' "$file"
\ foo\$bar\\baz\`

จากเอกสาร bash เมื่อprintf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)

วิธีนี้ใช้ไม่ได้กับบางกรณีเช่นเมื่อคุณต้องการเก็บเครื่องหมายคำพูดคู่ไว้
user3467349

@ user3467349 ใช้งานได้ดีกับคำพูด ฉันพนันได้เลยว่าคุณกำลังลองอะไรprintf '%s' "foo"อยู่ คุณต้องเข้าใจว่าการวิเคราะห์คำโต้แย้งทำงานอย่างไรในเชลล์ก่อน ดูgnu.org/software/bash/manual/bash.html#Shell-Operation # 2 เกิดขึ้นก่อน # 6
Patrick

คุณช่วยให้ตัวอย่างของสายนี้พิมพ์ด้วยprintfและไม่มีการจัดการอื่น ๆIt doesn't have a: ""
user3467349

printfปัญหาของคุณมีอะไรจะทำอย่างไรกับ ปัญหาของคุณคือคุณไม่ต้องการให้เชลล์วิเคราะห์สตริงของคุณ ในการทำเช่นนั้นคุณจะต้องส่งอินพุตของคุณไปยังเชลล์ในแบบที่มันไม่ได้พยายามแยกวิเคราะห์ วิธีหนึ่งในการทำเช่นนี้read -r -p 'input: ' && printf '%q\n' "$REPLY"คือจัดเตรียมอินพุตเมื่อได้รับพร้อมต์
Patrick

1
อย่างที่ฉันพูดไปหลายครั้งแล้ว การไม่รู้ว่าจะส่งข้อมูลดิบไปยังเชลล์นั้นไม่ได้เป็นปัญหาprintfหรือไม่ บางทีคุณควรถามคำถามแทนที่จะวิจารณ์วิธีแก้ปัญหาที่ไม่เกี่ยวข้องกับปัญหาของคุณ
แพทริค

4

ลอง:-

file=Dr\'\ A.tif
echo $file
Dr' A.tif

หรือ

file="Dr' A.tif"
echo $file
Dr' A.tif

หรือถ้าสตริงมีเครื่องหมายคำพูดคู่: -

file='Dr" A.tif'
echo $file
Dr" A.tif

มีบทเรียนที่ดีเกี่ยวกับการหลบหนีและการอ้างอิงบนเน็ต เริ่มต้นด้วยคนนี้


1

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

เนื่องจากคุณกำลังบ่วงผ่านการส่งออกของfind, นี้เป็นหนึ่งในวิธีที่ง่ายที่สุดเพื่อ (!) จัดการทุกเส้นทางที่เป็นไปได้ :

while IFS= read -r -d ''
do
    file_namex="$(basename -- "$REPLY"; echo x)"
    file_name="${file_namex%$'\nx'}"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)


-1

คำตอบเหล่านี้จำนวนมากรวมถึงคำตอบที่ได้รับการโหวตอันดับต้น ๆprintf "%q"จะไม่สามารถใช้งานได้ในทุกกรณีหากไม่มีการปรับแต่งเพิ่มเติม ฉันขอแนะนำต่อไปนี้ (ตัวอย่างด้านล่าง):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF


ยกตัวอย่างคำถามที่ n00b แต่คุณสามารถอธิบายรายละเอียดเกี่ยวกับวิธีที่คุณใช้เพื่อหนีอักขระในสตริงได้หรือไม่? หากฉันคัดลอกรหัสที่คุณเขียนลงในเทอร์มินัลฉันก็พิมพ์ 2015-11-07T03: 34: 41Z app [postgres.0000]: [TAG] ข้อความค้นหาค้นหาไม่มี lexemes: "" ... ไม่มีอะไรหลบหนี .
SharkAlley

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