Ingin membuat file txt untuk setiap png di folder

12

Saya punya skrip ini

#!/bin/bash

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

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

Ini berfungsi, hanya itu, untuk file bernama 001.png, itu menciptakan 001.png.txtbukan 001.txt.

Bagaimana saya bisa memodifikasi ini?

Qubix
sumber
4
Merupakan kebiasaan yang baik untuk mengutip variabel Anda. Shell script adalah bahasa aneh yang berkembang seiring waktu alih-alih dirancang dengan sempurna sejak awal, jadi sayangnya beberapa hal yang mengganggu seperti ini menjadi perlu. Tanpa mengutip variabel Anda, spasi putih atau tanda bintang di konten variabel akan menyebabkan hal-hal rusak dengan cara yang aneh. Untuk membuat skrip Anda lebih kuat, selalu mengelilingi penggunaan variabel Anda dengan tanda kutip ganda. Di sini, Anda akan mengatakan for filePng in "$folder"/*dan touch "$filePng".txt - perhatikan bahwa Anda hanya mengutipnya ketika didahului oleh a $.
Muzer
3
Ini terlihat seperti masalah XY ... Mengapa Anda mencoba melakukan ini?
JeromeJ

Jawaban:

16

Anda dapat menggunakan basenameperintah di sini:

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

Perhatikan tambahannya $folder/. Ini diperlukan karena perintah basename menghapus path dari.

Wayne_Yux
sumber
Bisakah saya menyarankan agar Anda mengutip ekspansi parameter dan substitusi perintah?
Tom Fenech
@ TomFenech ya, mungkin ide yang bagus untuk mengutip seluruh string. Saya mengedit jawaban saya.
Wayne_Yux
Saya tidak yakin mengapa Anda menghapus kutipan batin di sekitar $filePng- itu berguna juga.
Tom Fenech
1
Tidak, karena $( )menetapkan konteks kutipan baru.
Tom Fenech
2
Oh, Anda benar - pelajari sesuatu yang baru hari ini ;-)
Wayne_Yux
31

Anda dapat menghapus ekstensi yang ada menggunakan fitur ekspansi parameter shell

${parameter%pattern}'Pola' cocok dengan akhir 'parameter'. Hasilnya adalah nilai diperluas dari 'parameter' dengan kecocokan terpendek dihapus.

Jadi dalam kasus Anda, gantikan $filePng.txtdengan"${filePng%.png}.txt"

Steeldriver
sumber
10

Dengan variasi pada apa yang telah disebutkan steeldriver - ekspansi parameter - kita dapat menggunakan penggantian string untuk melakukan pekerjaan itu. Selain itu, Anda harus mengutip variabel. Di bawah ini adalah skrip Anda yang diedit.

#!/bin/bash

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

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

Jika Anda memiliki banyak file untuk membuatnya, ada baiknya “menyentuh” lebih dari satu file sekaligus, sehingga Anda tidak perlu melakukan proses baru untuk masing-masing file (yang membutuhkan waktu cukup lama jika dilakukan beberapa kali) seribu kali).

Opsi 1: substitusi pola + xargs

Opsi ini akan menyediakan beberapa jalur ke touchperintah sekaligus, biasanya beberapa ribu atau apa pun yang dapat ditampung sistem pada satu baris perintah.

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

Opsi 2: ekspansi parameter + pengarahan output perintah

Opsi ini tidak berjalan touchsama sekali tetapi menggunakan fitur shell Bash / Bourne / POSIX sebagai gantinya yang tidak memerlukan sub-proses sama sekali.

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

Jika Anda yakin bahwa Anda tidak memiliki file dengan .pngsuatu tempat di tengah nama, maka Anda bisa menggunakan array dengan ekspansi parameter:

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

Toko ini semua jalan ke file berakhiran .pngdalam array dan kemudian menggunakan ekspansi parameter untuk membuat daftar .txtfile, dengan menggantikan .pnguntuk.txt masing-masing satu.

Ingatlah bahwa ini akan pecah jika Anda memiliki begitu banyak file yang tidak dapat diteruskan sebagai argumen untuk permohonan yang sama touch.

Tom Fenech
sumber