Перегляньте всі файли з певним розширенням


109
for i in $(ls);do
    if [ $i = '*.java' ];then
        echo "I do something with the file $i"
    fi
done

Я хочу переглядати кожен файл у поточній папці і перевіряти, чи відповідає він певним розширенням. Код, описаний вище, не працює, ви знаєте, чому?


4
Про що for i in $(ls *.java); do echo "do something with file $i"; done?
доповідач

немає способу це виправити, якщо оператор?
AR89

1
Ви порівнюєте $iз буквальним рядком "* .java"; Розширення шаблону тут не виконується.
чепнер

Щоб виправити оператор if, як у вас є, використовуйте if [[ $i == *.java ]]; then.. (зверніть увагу на подвійний [[]] s і без котировки * .java).
той інший хлопець

2
Неls розбирайтеся - прийміть відповідь @ chepner
glenn jackman

Відповіді:


201

Не потрібні химерні трюки:

for i in *.java; do
    [ -f "$i" ] || break
    ...
done

Захисна програма гарантує, що якщо файлів, які не відповідають, цикл вийде, не намагаючись обробити неіснуюче ім'я файлу *.java. У bash(або оболонках, що підтримують щось подібне), ви можете використовувати nullglobопцію, щоб просто ігнорувати збій, що не відбувся, і не входити в тіло циклу.

shopt -s nullglob
for i in *.java; do
    ...
done

5
Найпростіший спосіб додати ще один шаблон: for i in *.java *.cpp; do. Якщо ви розширили шаблони включені в bashс shopt -s extglob, ви можете написати for i in *.@(java|cpp); do.
чепнер

8
Це буде, якщо він насправді відповідає будь-яким файлам. Вам потрібно використовувати shopt -s nullglobтак, щоб невідповідний шаблон розширювався до порожньої послідовності, а не розглядався буквально.
чепнер

1
@zygimantus так, так слід, доки в поточному каталозі знаходиться сценарій запуску. Якщо ви не в тому каталозі, яким ви хочете стати, вам слід cdдо цього каталогу, перш ніж запускати forцикл
danielsdesk

1
@puk Це залежить від ваших параметрів оболонки. За замовчуванням невідповідний шаблон трактується як буквальний рядок. Ви можете налаштувати так, nullglobщоб він трактувався як порожня послідовність, або встановити, failglobщоб він трактувався як помилка. (Якщо встановити обидва, failglobмає перевагу.)
Чепнер

3
@chepner Це може бути корисно для не експертів, щоб це було зазначено у відповіді, оскільки хтось може скопіювати його та вставити його. Прекрасним прикладом може бути той, хто перетворює всі " .jpg" файли в " .png", перш ніж виконувати вирішальну функцію
puk

13

правильна відповідь - це @ chepner's

EXT=java
for i in *.${EXT}; do
    ...
done

однак, ось невеликий трюк, щоб перевірити, чи має ім’я файлу дані розширення:

EXT=java
for i in *; do
    if [ "${i}" != "${i%.${EXT}}" ];then
        echo "I do something with the file $i"
    fi
done

як би було зі змінною extзамість .java?
AR89

13

Рекурсивно додайте підпапки,

for i in `find . -name "*.java" -type f`; do
    echo "$i"
done

замість того, find . -name "*.java" -type f -exec echo \{\} \; щоб уникнути помилкового виведення результатуfind
umläute

1
А якщо ви цього не зробите, принаймні, вам слід цитувати "$i"всередині циклу.
тріплей

2
Це не спрацює, якщо будь-який з файлів має пробіл у своєму імені.
codeforester

1
@codeforester У мене була саме ця проблема, і я її виправив, використовуючи метод з цієї відповіді: askubuntu.com/a/343753/551184
fsinisi90

7

Перебір всіх файлів , що закінчуються: .img, .bin, .txtсуфікс, і надрукувати ім'я файлу:

for i in *.img *.bin *.txt;
do
  echo "$i"
done

Або рекурсивним чином (знайдіть також у всіх підкаталогах):

for i in `find . -type f -name "*.img" -o -name "*.bin" -o -name "*.txt"`;
do
  echo "$i"
done

3

Я погоджуюся з іншими відповідями щодо правильного способу прокручування файлів. Однак ОП запитала:

Код, описаний вище, не працює, ви знаєте, чому?

Так!

Відмінна стаття Яка різниця між тестом, [та [[?] Докладно пояснює, що серед інших відмінностей ви не можете використовувати expression matchingабо pattern matchingв межах testкоманди (що є скороченою [)

Поставити новий тест [[старий тест [Приклад

Узгодження шаблону = (або ==) (недоступно) [[$ name = a *]] || echo "ім'я не починається з" a ": $ name"

Регулярне вираження = ~ (недоступно) [[$ (дата) = ~ ^ Пт \ ... \ 13]] && echo "П'ятниця 13-го!"
відповідність

Отже, це є причиною відмови вашого сценарію. Якщо ОП зацікавлена ​​у відповіді із [[синтаксисом (який має недолік, якщо він не підтримується на багатьох платформах, як [команда), я би радий відредагувати свою відповідь, щоб включити її.

EDIT: Будь-які підказки щодо того, як відформатувати дані у відповіді у вигляді таблиці, були б корисними!


2

як каже @chepner у своєму коментарі, ви порівнюєте $ i з фіксованою рядком.

Для розширення та виправлення ситуації слід скористатися [[]] з оператором регулярних виразів = ~

наприклад:

for i in $(ls);do
    if [[ $i =~ .*\.java$ ]];then
        echo "I want to do something with the file $i"
    fi
done

регулярне вираження праворуч від = ~ тестується на значення оператора лівої руки і не повинно бути цитуватися (цитується не буде помилкою, але порівняється з фіксованою рядком і так, швидше за все, не вдасться "

але відповідь @chepner вище за допомогою глобуса - набагато ефективніший механізм.


як би було зі змінною extзамість .java?
AR89

1
ак, не потрібно регулярного виразу: if [[ $i == *.java ]]або if [[ $i == *.$ext ]]. Але не
розбирайте

1

Я знайшов це рішення досить зручним. Він використовує -orпараметр у find:

find . -name \*.tex -or -name "*.png" -or -name "*.pdf"

Він буде шукати файли з розширенням tex, pngі pdf.

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