ข้อผิดพลาดสคริปต์ทุบตีกับสตริงที่มีเส้นทางที่มีช่องว่างและสัญลักษณ์


25

ฉันมีปัญหาในการเข้าใจพื้นฐานของการเขียนสคริปต์ Bash นี่คือสิ่งที่ฉันมี:

#!/bin/bash
FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
do
  echo "${f}"
done

สิ่งที่ฉันต้องการทำคือรายการ.txtไฟล์ทั้งหมดในforลูปเพื่อให้ฉันสามารถทำสิ่งกับพวกเขา แต่พื้นที่ในmy directoryและเครื่องหมายดอกจันใน*.txtเพียงไม่เล่นอย่าง ฉันลองใช้มันโดยไม่ใส่เครื่องหมายอัญประกาศคู่โดยมีและไม่มีเครื่องหมายปีกกาบนชื่อตัวแปรและยังไม่สามารถพิมพ์.txtไฟล์ทั้งหมดได้

นี่เป็นสิ่งพื้นฐานมาก แต่ฉันยังคงดิ้นรนเพราะฉันเหนื่อยและคิดไม่ออก

ผมทำอะไรผิดหรือเปล่า?

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

คำตอบ:


33

ภายในเครื่องหมายคำพูด*จะไม่ขยายไปยังรายการไฟล์ หากต้องการใช้ไวด์การ์ดดังกล่าวสำเร็จจะต้องอยู่นอกเครื่องหมายคำพูด

แม้ว่าอักขระตัวแทนจะขยายตัวนิพจน์"${FILES}"จะส่งผลให้มีสตริงเดียวไม่ใช่รายการไฟล์

วิธีการหนึ่งที่จะสามารถใช้ได้คือ:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

ในข้างต้นชื่อไฟล์ที่มีช่องว่างหรือตัวอักษรที่ยากอื่น ๆ จะถูกจัดการอย่างถูกต้อง

วิธีการขั้นสูงเพิ่มเติมสามารถใช้อาร์เรย์ bash:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

ในกรณีนี้FILESคืออาร์เรย์ของชื่อไฟล์ parens ที่ล้อมรอบนิยามทำให้เป็นอาร์เรย์ โปรดทราบว่า*อยู่นอกคำพูด โครงสร้าง"${FILES[@]}"เป็นกรณีพิเศษ: มันจะขยายไปยังรายการของสตริงที่แต่ละสตริงเป็นหนึ่งในชื่อไฟล์ ชื่อไฟล์ที่มีช่องว่างหรืออักขระที่ยากอื่น ๆ จะได้รับการจัดการอย่างถูกต้อง


1
ยอดเยี่ยมที่ใช้ได้
John

มันน่าสังเกตว่าถ้าคุณผ่านเส้นทางแบบนี้ไปรอบ ๆ ฟังก์ชั่นคุณต้องแน่ใจว่าคุณพูดตัวแปรด้วยตัวเองแทนที่จะต่อมันเป็นส่วนหนึ่งของสตริงที่มีขนาดใหญ่กว่า: for f in "$DIR"/*.txt= fine for f in "$DIR/*.txt"= break
pospi

7

ในขณะที่ใช้อาร์เรย์ดังที่ John1024 มีความหมายมากขึ้นที่นี่คุณยังสามารถใช้ตัวดำเนินการแยก + glob (ปล่อยตัวแปรสเกลาร์ไว้โดยไม่มีการอ้างอิง)

เนื่องจากคุณต้องการเพียงส่วน glob ของผู้ประกอบการนั้นคุณต้องปิดการใช้งานส่วนแยก :

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done

0

สิ่งที่คุณสามารถทำได้คือการทิ้งอักขระไวด์การ์ดไว้นอกเครื่องหมายคำพูด
สิ่งที่ต้องการ:
สำหรับใน "ไฟล์ที่มีช่องว่าง" * ". txt"
ทำการ
ประมวลผล
เสร็จแล้ว
หากอักขระตัวแทนขยายออกเป็นช่องว่างคุณจะต้องใช้ไฟล์ตามวิธีการต่อบรรทัดเช่นใช้ ls -l เพื่อสร้างรายการของ ไฟล์และใช้ bash read เพื่อรับแต่ละไฟล์


-1

เมื่อคุณต้องการประมวลผลชุดไฟล์คุณจะต้องพิจารณาว่าชื่อของพวกเขาคือช่องว่างหรือโค้ดสเคปอื่น ๆ จะอยู่ที่นั่นดังนั้นก่อนที่จะเริ่มกระบวนการของคุณเช่นfor loopหรือfind commandตั้งค่าเป็นIFS bash env variable:

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