ต้องการสร้างไฟล์ txt สำหรับทุก png ในโฟลเดอร์


12

ฉันมีสคริปต์นี้

#!/bin/bash

folder='/home/data/mnist/training'

for filePng in $folder/*
do
touch $filePng.txt
done

มันใช้งานได้ดีสำหรับไฟล์ที่ชื่อ001.pngมันจะสร้างขึ้น001.png.txtแทน001.txtแทน

ฉันจะแก้ไขสิ่งนี้ได้อย่างไร


4
มันเป็นนิสัยที่ดีในการพูดตัวแปรของคุณ เชลล์สคริปเป็นภาษาแปลก ๆ ที่พัฒนาไปตามกาลเวลาแทนที่จะได้รับการออกแบบอย่างสมบูรณ์แบบตั้งแต่เริ่มต้นดังนั้นน่าเสียดายที่บางสิ่งที่น่ารำคาญเช่นนี้กลายเป็นสิ่งจำเป็น โดยไม่ต้องอ้างอิงตัวแปรของคุณช่องว่างหรือเครื่องหมายดอกจันในเนื้อหาตัวแปรจะทำให้สิ่งต่าง ๆ แตกสลายด้วยวิธีแปลก ๆ เพื่อให้สคริปต์ของคุณมีประสิทธิภาพมากขึ้นให้ใช้ตัวแปรของคุณด้วยเครื่องหมายคำพูดคู่ ที่นี่คุณจะพูดfor filePng in "$folder"/*และtouch "$filePng".txt - หมายเหตุ: $คุณพูดพวกเขาเมื่อนำหน้าด้วย
Muzer

3
ดูเหมือนว่าปัญหา XY ... ทำไมคุณจึงลองทำเช่นนี้
JeromeJ

คำตอบ:


16

คุณสามารถใช้basenameคำสั่งได้ที่นี่:

touch "$folder/$(basename "$filePng" .png).txt"

$folder/หมายเหตุเพิ่มเติม นี่เป็นสิ่งจำเป็นเนื่องจากคำสั่ง basename จะลบพา ธ ออก


ฉันขอแนะนำให้คุณยกการขยายพารามิเตอร์และการทดแทนคำสั่งของคุณ?
Tom Fenech

@ TomFenech ใช่อาจเป็นความคิดที่ดีที่จะพูดถึงสตริงทั้งหมด ฉันแก้ไขคำตอบของฉัน
Wayne_Yux

ฉันไม่แน่ใจว่าทำไมคุณลบคำพูดภายในออกไป$filePng- มันมีประโยชน์เช่นกัน
Tom Fenech

1
ไม่เพราะ$( )สร้างบริบทการอ้างอิงใหม่
Tom Fenech

2
โอ้คุณพูดถูกแล้ว - เรียนรู้สิ่งใหม่วันนี้ ;-)
Wayne_Yux

31

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

${parameter%pattern}'รูปแบบ' ตรงกับจุดสิ้นสุดของ 'พารามิเตอร์' ผลลัพธ์คือค่าที่ขยายของ 'พารามิเตอร์' พร้อมลบการจับคู่ที่สั้นที่สุด

ดังนั้นในกรณีของคุณแทนที่$filePng.txtด้วย"${filePng%.png}.txt"


10

ด้วยความผันแปรของสิ่งที่ Steeldriver ได้กล่าวถึงแล้ว - การขยายพารามิเตอร์ - เราสามารถใช้การแทนที่สตริงเพื่อทำงาน นอกจากนี้คุณควรอ้างอิงตัวแปร ด้านล่างเป็นสคริปต์ที่แก้ไขของคุณ

#!/bin/bash

folder='/home/data/mnist/training'

for filePng in "$folder"/*
do
    touch "${filePng/.png/.txt}"
done

9

หากคุณมีมากไฟล์จะสร้างมันจะคุ้มค่าที่จะ "แตะ" มากกว่าหนึ่งไฟล์ในแต่ละครั้งดังนั้นคุณไม่จำเป็นต้องแยกกระบวนการใหม่ให้กับแต่ละไฟล์ (ซึ่งใช้เวลาค่อนข้างนานในการดำเนินการหลายอย่าง พันครั้ง)

ตัวเลือกที่ 1: การทดแทนรูปแบบ + xargs

ตัวเลือกนี้จะให้หลายเส้นทางไปยังtouchคำสั่งในครั้งเดียวมักจะไม่กี่พันหรืออะไรก็ตามที่ระบบสามารถพอดีกับบรรทัดคำสั่งเดียว

find "$folder" -mindepth 1 -maxdepth 1 -name '*.png' -print0 |
sed -ze 's/\.png$/.txt/' |
xargs -r0 -- touch --

ตัวเลือกที่ 2: การขยายพารามิเตอร์ + คำสั่งการเปลี่ยนเส้นทางออก

ตัวเลือกนี้ไม่ทำงานtouchเลย แต่ใช้คุณลักษณะเชลล์ของ Bash / Bourne / POSIX แทนซึ่งไม่ต้องการกระบวนการย่อยเลย

for f in "$folder"/*.png; do
    : >> "${f%.png}.txt"
done

4

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

pngs=( /path/to/pngs/*.png )
touch "${pngs[@]/.png/.txt}"

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

touchจำไว้ว่านี้จะแตกถ้าคุณมีไฟล์จำนวนมากที่พวกเขาไม่สามารถทั้งหมดจะผ่านอาร์กิวเมนต์ไปที่ภาวนาเดียวกันของ

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