Перевірте, чи існує в каталозі певний тип / розширення файлу


84

Як би ви розповіли, чи є файли певного розширення в каталозі за допомогою bash?

Щось на зразок

if [ -e *.flac ]; then 
echo true; 
fi 

Відповіді:


104
#!/bin/bash

count=`ls -1 *.flac 2>/dev/null | wc -l`
if [ $count != 0 ]
then 
echo true
fi 

9
Ей, Томасе, як щодо додавання кращого рішення питання, а не просто проти.
JeremyWeir

8
Також Томас, ваш приклад, чому не використовувати його, використовує ls -lмоя відповідьls -1
JeremyWeir

10
І ця відповідь не аналізує вихідні дані, вона просто підраховує вихідні рядки, і я майже впевнений, навіть якщо в назві файлу є дивні символи, ls -1збирається надрукувати один рядок у файлі
JeremyWeir

2
Підрахунок рядків проводиться синтаксичний аналіз. І він поверне неправильний номер, якщо який-небудь файл містить \n(і так, це дійсно в іменах файлів).
marcelm

1
Помоліться, скажіть тоді, який магічний персонаж повинен бути в назві файлу, щоб рядок не рахувався?
yeoman

27
#/bin/bash

myarray=(`find ./ -maxdepth 1 -name "*.py"`)
if [ ${#myarray[@]} -gt 0 ]; then 
    echo true 
else 
    echo false
fi

5
Цей приємний, тому що ви насправді можете щось зробити з файлами після того, як їх знайдете.
ephsmith

+1 для обгортання підшарки, що виконується find у дужках, щоб зробити myarray змінною масиву. В іншому випадку, якщо find повертає, жоден результат не ${#myarray[@]}дорівнює 1
shaffooo

також може спростити, використовуючи ls -1 *.pyзамість пошуку
JrBenito

Якщо в назві будь-якого з файлів є пробіл, це буде зараховувати один примірник як два.
Джон Гріффіт,

16

Тут використовується ls (1), якщо файлів flac не існує, ls повідомляє про помилку і сценарій виходить; в іншому випадку сценарій продовжується, і файли можуть бути оброблені

#! /bin/sh
ls *.flac  >/dev/null || exit
## Do something with flac files here

4
Для додаткової тиші також переспрямуйте 2> & 1.
Джаспер

6
Версія if:if ls *.flac >/dev/null 2>&1; then ... fi;
Джосія Йодер


4

Вам слід бути уважними, який прапор ви кидаєте у свою ifзаяву, і як це пов’язано з результатом, який ви хочете.

Якщо ви хочете перевірити лише звичайні файли, а не інші типи файлової системи, тоді вам потрібно змінити скелет коду на:

if [ -f file ]; then
echo true;
fi

Використання -fобмежує ifдо звичайних файлів, тоді як воно -eє більш обширним і відповідатиме всім типам записів файлової системи. Звичайно, є й інші варіанти, наприклад, -dдля каталогів тощо. Для отримання хорошого списку див. Http://tldp.org/LDP/abs/html/fto.html .

Як зазначає @msw, test(тобто [) задихнеться, якщо ви спробуєте подати його більше одного аргументу. Це може статися у вашому випадку, якщо glob для *.flacповернув більше одного файлу. У такому випадку спробуйте обернути ifтест у цикл, як:

for file in ./*.pdf
do
    if [ -f "${file}" ]; then
    echo 'true';
    break
    fi
done

Таким чином ви перейдете breakдо першого екземпляра потрібного вам розширення файлу і зможете продовжувати роботу з рештою сценарію.


1
за винятком test(aka [) скаржиться, якщо шаблон розширюється до більш ніж одного файлу: "двійковий оператор очікується" або "занадто багато аргументів"
msw

1
@msw - дякую, я навіть не замислювався над цим питанням. Я намагався змінити свою відповідь, щоб врахувати її.
dtlussier

Вам слід навести змінну, тобто використовувати "$file", оскільки ім'я файлу може містити деякі неправильні символи, такі як пробіли або зірочки.
Роман Чепляка,

3
#!/bin/bash
files=$(ls /home/somedir/*.flac 2> /dev/null | wc -l)
if [ "$files" != "0" ]
then
echo "Some files exists."
else
echo "No files with that extension."
fi

3

Найкраще рішення (if [ -e *.flac ];)для мене не спрацювало, давши:[: too many arguments

if ls *.flac >/dev/null 2>&1; тоді це спрацює.


3

Ви можете використовувати -f, щоб перевірити, чи існують файли певного типу:

#!/bin/bash

if [ -f *.flac ] ; then
   echo true
fi 

Це працює, але ви ховаєте світлодіод - причина, по якій він працює, полягає в тому, що одна дужка [(на відміну від найпоширенішої [[) не перешкоджає глобінгу.
Адріан Петреску

2
   shopt -s nullglob
   set -- $(echo *.ext)
    if [ "${#}" -gt 0 ];then
      echo "got file"
    fi

Це неправильно. По-перше, ви, мабуть, мали на увазі -geзамість -gt, тому що інакше ваш код не виявить окремий файл. По-друге, якщо немає файлів, що відповідають шаблону, будь-яка відповідна оболонка залишить рядок *.extнедоторканим, тому ви все одно отримаєте один "результат".
Роман Чепляка,

$ # - це 1 для окремого файлу та 0 для жодного файлу.
фрайзер

1

лише баш:

any_with_ext () ( 
    ext="$1"
    any=false
    shopt -s nullglob
    for f in *."$ext"; do
        any=true
        break
    done
    echo $any 
)

if $( any_with_ext flac ); then
    echo "have some flac"
else 
    echo "dir is flac-free"
fi

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


1

Ось рішення, яке не використовує зовнішніх команд (тобто ні ls), а замість цього функцію оболонки. Перевірено в bash:

shopt -s nullglob
function have_any() {
    [ $# -gt 0 ]
}

if have_any ./*.flac; then
    echo true
fi

Функція have_anyвикористовує $#для підрахунку своїх аргументів, а [ $# -gt 0 ]потім перевіряє, чи є хоча б один аргумент. Застосування ./*.flacзамість просто *.flacу виклику have_any, щоб уникнути проблем, викликаних файлами з іменами типу --help.


1

Для завершення, з zsh:

if [[ -n *.flac(#qN) ]]; then
  echo true
fi

Це вказано в кінці розділу Умовні вирази в посібнику zsh. Оскільки [[відключає глобалізацію імені файлу, нам потрібно примусити генерацію імені файлу, використовуючи (#q)кінець рядка глобування, а потім Nпрапор ( NULL_GLOBопція), щоб змусити згенерований рядок бути порожнім, якщо не буде збігу.


1

Ось досить просте рішення:

if [ "$(ls -A | grep -i \\.flac\$)" ]; then echo true; fi

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


мені це подобається, тому що ls -AR робить рекурсивний пошук. добре для пошуку вмісту архівів zip після розпакування.
Джастін Кресс

0

Я спробував це:

if [ -f *.html ]; then
    echo "html files exist"
else
    echo "html files dont exist"
fi

Я використав цей фрагмент коду без будь-яких проблем для інших файлів, але для файлів html отримав повідомлення про помилку :

[: too many arguments

Потім я спробував рішення підрахунку @ JeremyWeir, яке мені підходило.

Майте на увазі, вам доведеться скинути рахунок, якщо ви робите це в циклі:

count=$((0))

0

Це має працювати в будь-якій оболонці, подібній до несеного:

if [ "$(find . -maxdepth 1 -type f | grep -i '.*\.flac$')" ]; then
    echo true
fi

Це також працює з GNU find, але IDK, якщо це сумісно з іншими реалізаціями find:

if [ "$(find . -maxdepth 1 -type f -iname \*.flac)" ]; then
    echo true
fi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.