Помилка сценарію Bash з рядками з шляхами, які мають пробіли та символи


25

У мене виникають проблеми з тим, як звалити основи сценаріїв Баша. Ось що я маю досі:

#!/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це масив імен файлів. Парени, що оточують визначення, роблять його масивом. Зауважте, що *котирування є поза межами. Конструкція "${FILES[@]}"є окремим випадком: вона розшириться до списку рядків, де кожна рядок є одним із назв файлів. Імена файлів із пробілами чи іншими складними символами будуть правильно оброблятися.


1
чудово, що спрацювало
Іван

Варто зазначити, що якщо ви передаєте такі шляхи навколо функцій, вам потрібно переконатися, що ви цитуєте змінну самостійно, а не об'єднуючи її як частину більшого рядка: for f in "$DIR"/*.txt= fine for f in "$DIR/*.txt"= перерви
pospi

7

Хоча використання масивів, як показано John1024, має набагато більше сенсу, тут ви також можете використовувати оператор split + 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, щоб отримати кожен файл.


-1

Коли ви хочете обробити набір файлів, ви вважаєте, у їх імені може бути пробіл, або інший код скапу буде там, тому перед запуском процесу, наприклад, for loopабо find commandвстановіть IFS bash env variable:

IFS=$(echo -en "\n\b")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.