2012-06-21 3 views
17

Использование bash, как можно получить количество файлов в папке, исключая каталоги из сценария оболочки без запроса интерпретатора?Как получить количество файлов в папке в виде переменной?

С помощью друга, я попытался

$files=$(find ../ -maxdepth 1 -type f | sort -n) 
$num=$("ls -l" | "grep ^-" | "wc -l") 

, который возвращает из командной строки:

../1-prefix_blended_fused.jpg: No such file or directory 
ls -l : command not found 
grep ^-: command not found 
wc -l: command not found 

соответственно. Эти команды работают в командной строке, но НЕ с помощью сценария bash.

Учитывая, что файл заполнен файлами изображений, отформатированными как 1-pano.jpg, я хочу захватить все изображения в каталоге, чтобы получить самый большой нумерованный файл, который будет привязан к следующему обрабатываемому изображению.

Почему разница?

+0

Что такое цитаты вокруг ваших команд? – sarnold

+0

Также, избавляйтесь от знаков доллара при назначении переменной; 'files = $ (find ...)' и 'num = $ (ls -l ...)'. – chepner

+0

@sarnold, несколько учебников по сценариям говорят о том, что наличие пробелов внутри блоков исполнения - это плохо, и использовать двойные кавычки для облегчения риска. – Jason

ответ

32

Кавычки приводит к появлению сообщений об ошибках.

Чтобы получить количество файлов в каталоге:

shopt -s nullglob 
numfiles=(*) 
numfiles=${#numfiles[@]} 

, которая создает массив, а затем заменяет его с графом ее элементов. Это будут файлы и каталоги, но не dotfiles или . или .. или другие точечные каталоги.

Используйте nullglob так пустой каталог дает подсчет 0 вместо 1.

Вы можете использовать вместо find -type f или вы можете рассчитывать каталоги и вычитать:

# continuing from above 
numdirs=(*/) 
numdirs=${#numdirs[@]} 
((numfiles -= numdirs)) 

Также смотрите «How can I find the latest (newest, earliest, oldest) file in a directory?»

Внутри блока выполнения может быть столько же, сколько требуется. Они часто помогают в удобочитаемости. Единственным недостатком является то, что они делают файл немного большим и могут немного замедлить первоначальный синтаксический анализ (только). Есть несколько мест, которые должны иметь места (например, вокруг [, [[, ], ]] и = в сравнении) и несколько, которые не должны (например, вокруг = в назначении

+0

bash array - это слишком много для такой использование !! (становятся медленными, когда они большие) – neam

+0

Удивительный способ сделать это .. .thx –

+0

'numfiles = (*); numfiles = $ {# numfiles [@]} 'в пустом каталоге возвращает' 1' – Meisner

1

Избавьтесь от котировок. Оболочка обрабатывает их как один файл, поэтому он ищет «ls -l».

10

Как насчет:.

count=$(find .. -maxdepth 1 -type f|wc -l) 
echo $count 
let count=count+1 # Increase by one, for the next file number 
echo $count 

Обратите внимание, что это решение не является эффективным: он порождает суб оболочки для команд find и wc, но он должен работать

+0

Это похоже на то, что я делал. Кроме того, эффективность в микросекундах не слишком беспокоит, так как эта команда будет выполняться с интервалом примерно 20-40 минут. – Jason

+0

Точно; если вы правильно используете конвейерную обработку, ни один из икры не будет во внутреннем цикле. Ну, они все будут частью конвейера конвейера; но они не будут узким местом. –

2

file_num=$(ls -1 --file-type | grep -v '/$' | wc -l)

01.

Это немного легче, чем команда find, и подсчитывает все файлы текущего каталога.

+1

Для меня 'ls -1 --file-type' возвращает' ls: незаконный вариант - -'. Если вы собираетесь предоставить решение для конкретного поставщика, по крайней мере, упомяните поставщика. Кроме того, это не исключает символические ссылки. – ghoti

0

Простой эффективный метод:

#!/bin/bash 
RES=$(find ${SOURCE} -type f | wc -l) 
+3

Можете ли вы дать краткое объяснение, почему это работает? Демпинг кода (обычно) обескуражен, потому что OP может не знать достаточно о синтаксисе, чтобы полностью понять, что вы пытаетесь сделать. – rayryeng

+1

Будьте осторожны, это не сработает, если в каталоге есть имена файлов с разрывами строк. –

8
ls -l | grep -v ^d | wc -l 

Одна линия.

+1

Это не совсем правильно. Этот вызов в большинстве случаев включает в себя «общую строку » (и, следовательно, считать слишком много, см. Http://stackoverflow.com/questions/7401704/what-is-that-total-in-the-very- первая линия-после-LS-л).Добавьте подстановочный знак, чтобы предотвратить это: ls -l * | grep -v^d | wc -1 –

+0

Хорошо заметили, возможно: ls -l | grep -v^d | grep -v^t | wc -l. – mckenzm

+0

Да, это будет работать нормально. –

0

Расширение принятого ответа (Деннис W): когда я пробовал этот подход, у меня были неправильные подсчеты для dirs без подкаталогов в Bash 4.4.5.

Проблема заключается в том, что по умолчанию nullglob не установлен в Bash, а numdirs=(*/) устанавливает массив из 1 элемента с шаблоном glob */. Аналогично, я подозреваю, что у numfiles=(*) будет 1 элемент для пустой папки.

Установка shopt -s nullglob, чтобы отключить nullglobbing, решает проблему для меня. Для отличной дискуссии о том, почему nullglob не задан по умолчанию на Bash, см. Ответ здесь: Why is nullglob not default?

Примечание: Я бы прокомментировал ответ напрямую, но не имел точек репутации.

Смежные вопросы