Я хочу проверить количество файлов внутри папки и хочу, чтобы результат, например, был умножен на 4. Я попробовал что-то вроде:
cd path/to/my/folder && find . -maxdepth 1 -type f | wc -l | expr {} * 4
Но это не работает. Это работает до тех пор, пока:
cd path/to/my/folder && find . -maxdepth 1 -type f | wc -l
Но когда я добавляю что-то вроде "expr {} * 4", я получаю сообщение об ошибке... Я также пробовал другие альтернативы «expr», но пока безуспешно.
Кстати, я также хочу, чтобы результат можно было передать в другую программу, например ffmpeg, что-то вроде:
cd path/to/my/folder && find . -maxdepth 1 -type f | wc -l | expr {} * 4 | ffmpeg -i {} out.mp4
Выше приведен глупый пример, призванный упростить то, что я пытаюсь сделать... Для любопытных я использую https://github.com/nihui/rife-ncnn-vulkan, чтобы увеличить количество кадров/частоту кадров в четыре раза. видео, поэтому мне нужно проверить количество файлов (изображений) внутри папки, автоматически умножить число на 4 и поместить результат в параметр «-n» rife-ncnn-vulkan... Так что более реалистичный вариант команда будет примерно такой:
ffmpeg -i "video.mkv" -r 12 -c:v libwebp -lossless 1 -y input_frames/frame_%06d.webp && cd input_frames && find . -maxdepth 1 -type f | wc -l | expr {} * 4 | rife-ncnn-vulkan -i input_frames -o output_frames -f %08d.webp -x -v -n {}
(обратите внимание на «{}» в самом конце, где я хочу поместить результат математической операции).
(если команда shopt выдает ошибку, это означает, что ваша оболочка на самом деле не bash — не используйте sh для запуска сценариев bash)





Это работает в bash и zsh:
cd path/to/my/folder
let count = "$(find . -type f -maxdepth 1 | wc -l) * 4"
rife-ncnn-vulkan ... -n $count
Команда let позволяет оболочке выполнять арифметические действия.
Спасибо Чарльзу Даффи за предложение. Вот перезапись расчета:
count = "$(( $(find . -type f -maxdepth 1 | wc -l) * 4 ))"
let — артефакт из ракушек 1980-х годов. Современный арифметический синтаксис, совместимый с POSIX, который все еще работает в ksh88 и его духовных преемниках, таких как bash и zsh, но дополнительно поддерживается в ash, Dash и других реализациях POSIX sh, вместо этого использует $(( )).
Я показываю свой возраст :)
Эй, спасибо за ответ... Вроде работает!... вроде... странно, когда запускаю команду, она не работает... с первого раза. Затем я передаю его в "echo $count", чтобы посмотреть, что происходит, а также ничего... Затем я запускаю его, не передавая его в команду Anyhitng, а затем, еще раз, я запускаю его, передавая его в "echo $count". "и это работает... странно!
@CharlesDuffy, не могли бы вы рассказать об этом подробнее?
@tuqueque, используйте set -x, чтобы включить ведение журнала трассировки. Тем не менее, «передача по конвейеру в эхо» сама по себе является проблемой: вам никогда не следует передавать по каналу в эхо, поскольку echo не читает из стандартного ввода, поэтому оно игнорирует все, что передается по конвейеру. Единственная трубка в этом ответе — между find и wc — больше не добавляйте.
@tuqueque, ... Еще одна вещь, которую следует иметь в виду в отношении каналов, это то, что каждая часть конвейера выполняется в отдельном процессе от других частей, поэтому, если вы устанавливаете переменную в компоненте конвейера, это обычно (с некоторыми исключениями, которые здесь не важны), отбрасываются после выхода из конвейера. Это актуально только в том случае, если вы используете каналы там, где они неуместны, поэтому будьте осторожны, не делайте этого; используйте каналы только для подключения стандартного вывода одного процесса к стандартному вводу другого.
{} не заменяет ввод, это просто строка, которая будет передана буквально в качестве аргумента. Но вы можете использовать xargs для захвата ввода и передачи его в качестве аргумента(ов). Вы можете использовать что-то вроде -I{}, чтобы использовать {} (или любую другую строку, которую вы предпочитаете) в качестве заполнителя для входного значения, например:
find . -maxdepth 1 -type f | wc -l | xargs -I{} expr {} "*" 4
Или не используйте заполнитель, в этом случае захваченный ввод будет добавлен в конец команды, поэтому вам нужно изменить выражение:
find . -maxdepth 1 -type f | wc -l | xargs expr 4 "*"
Обратите внимание, что в любом случае вы должны заключить * в кавычки или экранировать его, иначе оболочка расширит его до списка имен файлов в каталоге, а не передаст его как буквальный символ звездочки.
Стоит четко указать (поскольку это читает новичок), что expr вообще следует избегать в новом коде — это артефакт 1970-х годов, еще до того, как оболочки имели встроенную математическую поддержку. Если необходимо использовать передаваемые по конвейеру значения (и, следовательно, xargs), тогда нужна внешняя команда, и выражение является разумным, но я не уверен, что это на самом деле требование, а не случайность реализации.
Извините за поздний ответ... После тестирования всех вариантов, это почти то, что я искал (с небольшой модификацией). Я знаю, что это не самый элегантный или «современный» способ решения задач, но я, по сути, искал простой и понятный способ сделать это и, что более важно, я хочу решать проблемы с помощью однострочников.
Демонстрация того, как применить ответ, который написал Хай Ву, к коду, показанному в вопросе:
ffmpeg \
-i "video.mkv" \
-r 12 \
-c:v libwebp \
-lossless 1 \
-y input_frames/frame_%06d.webp || exit
count=$(( $(find input_frames -maxdepth 1 -type f -print | wc -l) * 4 )) || exit
rife-ncnn-vulkan -x -v \
-i input_frames \
-o output_frames \
-f %08d.webp \
-n "$count" || exit
Уведомление:
&&, мы заканчиваем их || exit; это имеет тот же эффект, но более удобен в обслуживании.find и wc (и в некоторых версиях find есть действие -count; если бы мы использовали это, нам бы тоже не понадобилось wc).cd input_frames. Если бы мы это сделали, это изменило бы каталог, в котором работает вторая копия ffmpeg, но вы хотите изменить только каталог, с которым работает find — мы можем сделать это, просто изменив . на input_frames.count в переменной и используем эту переменную позже, не передавая значение по конвейеру.
Кстати, я не уверен, что вам вообще нужно использовать
findилиwc. Например,shopt -s nullglob; frames=( input_frames/*.webp ); frame_count=${#frames[@]}сохранит количество совпадающих имен вframe_countбез вызова какого-либо инструмента, и после того, как вы это сделаете,$(( frame_count * 4 ))расширится до желаемого множителя.