Хочете створити 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
Це корисна звичка цитувати свої змінні. Шрифт Shell - це дивна мова, яка розвивалася з часом, а не була ідеально розроблена під час руху, тому, на жаль, деякі набридливі речі на кшталт цього стають необхідними. Без цитування змінних, пробіли чи зірочки у вмісті змінної можуть призвести до розбиття речей дивними способами. Щоб зробити ваші сценарії більш надійними, завжди оточуйте використання своїх змінних подвійними лапками. Ось, ви б сказали, for filePng in "$folder"/*і touch "$filePng".txt - зауважте, ви цитуєте їх лише тоді, коли перейдете до а $.
Мюзер

3
Це виглядає як проблема XY ... Чому ви намагаєтеся це зробити?
JeromeJ

Відповіді:


16

Ви можете використовувати basenameкоманду тут:

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

Зверніть увагу на додаткове $folder/. Це необхідно, оскільки команда basename видаляє шлях з.


Чи можу я запропонувати вам вказати розширення параметрів та заміну команд?
Том Фенек

@TomFenech Так, напевно, хороша ідея, щоб процитувати цілий рядок. Я відредагував свою відповідь.
Wayne_Yux

Я не впевнений, чому ви видалили внутрішні цитати навколо $filePng- вони теж були корисними.
Том Фенек

1
Ні, тому що $( )встановлює новий контекст цитування.
Том Фенек

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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.