Как я могу выполнить математическую операцию с результатом «wc -l»?

Я хочу проверить количество файлов внутри папки и хочу, чтобы результат, например, был умножен на 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 {}

(обратите внимание на «{}» в самом конце, где я хочу поместить результат математической операции).

Кстати, я не уверен, что вам вообще нужно использовать find или wc. Например, shopt -s nullglob; frames=( input_frames/*.webp ); frame_count=${#frames[@]} сохранит количество совпадающих имен в frame_count без вызова какого-либо инструмента, и после того, как вы это сделаете, $(( frame_count * 4 )) расширится до желаемого множителя.

Charles Duffy 19.05.2024 03:29

(если команда shopt выдает ошибку, это означает, что ваша оболочка на самом деле не bash — не используйте sh для запуска сценариев bash)

Charles Duffy 19.05.2024 13:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
81
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это работает в 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, вместо этого использует $(( )).
Charles Duffy 19.05.2024 00:39

Я показываю свой возраст :)

Hai Vu 19.05.2024 00:52

Эй, спасибо за ответ... Вроде работает!... вроде... странно, когда запускаю команду, она не работает... с первого раза. Затем я передаю его в "echo $count", чтобы посмотреть, что происходит, а также ничего... Затем я запускаю его, не передавая его в команду Anyhitng, а затем, еще раз, я запускаю его, передавая его в "echo $count". "и это работает... странно!

tuqueque 19.05.2024 02:37

@CharlesDuffy, не могли бы вы рассказать об этом подробнее?

tuqueque 19.05.2024 02:39

@tuqueque, используйте set -x, чтобы включить ведение журнала трассировки. Тем не менее, «передача по конвейеру в эхо» сама по себе является проблемой: вам никогда не следует передавать по каналу в эхо, поскольку echo не читает из стандартного ввода, поэтому оно игнорирует все, что передается по конвейеру. Единственная трубка в этом ответе — между find и wc — больше не добавляйте.

Charles Duffy 19.05.2024 03:07

@tuqueque, ... Еще одна вещь, которую следует иметь в виду в отношении каналов, это то, что каждая часть конвейера выполняется в отдельном процессе от других частей, поэтому, если вы устанавливаете переменную в компоненте конвейера, это обычно (с некоторыми исключениями, которые здесь не важны), отбрасываются после выхода из конвейера. Это актуально только в том случае, если вы используете каналы там, где они неуместны, поэтому будьте осторожны, не делайте этого; используйте каналы только для подключения стандартного вывода одного процесса к стандартному вводу другого.

Charles Duffy 19.05.2024 03:12
Ответ принят как подходящий

{} не заменяет ввод, это просто строка, которая будет передана буквально в качестве аргумента. Но вы можете использовать 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), тогда нужна внешняя команда, и выражение является разумным, но я не уверен, что это на самом деле требование, а не случайность реализации.

Charles Duffy 19.05.2024 03:19

Извините за поздний ответ... После тестирования всех вариантов, это почти то, что я искал (с небольшой модификацией). Я знаю, что это не самый элегантный или «современный» способ решения задач, но я, по сути, искал простой и понятный способ сделать это и, что более важно, я хочу решать проблемы с помощью однострочников.

tuqueque 21.05.2024 13:34

Демонстрация того, как применить ответ, который написал Хай Ву, к коду, показанному в вопросе:

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 в переменной и используем эту переменную позже, не передавая значение по конвейеру.
  • Пробелы во многом улучшают читаемость.

Другие вопросы по теме

Похожие вопросы

Переменная не установлена ​​ошибка в docker-compose с использованием переменных bash
Как я могу преобразовать строку в число в bash?
Рекурсивное выполнение нескольких команд для определенного файла, если он найден в каталоге
Как можно извлечь одну строку данных из файла и другого процесса в каждой этой строке?
Непоследовательные результаты журнала git при фильтрации по каталогу
Цитирование команды оболочки внутри команды osascript, запускаемой оболочкой внутри файла JSON
Как избежать ошибки «Неверный тип аргумента» при выполнении, казалось бы, допустимой команды AWS CLI, созданной с использованием jq и bash?
Как найти одинаковые файлы в дереве каталогов
Используйте вывод сценария с кавычками в качестве аргументов командной строки
Microchip MPLAB X IDE: настройка и запуск общего сценария Bash перед сборкой, который работает как в Windows, так и в Linux как часть процесса сборки