Вопрос или проблема
Я запустил эту команду:
ls -1 | xargs -I% -n1 -P8 myprogramm -s1 -r5 -q -o %.dat %
Она выполняется с 8 запусками одновременно, переключатель -q
в myprogramm отвечает за выход, так что это нормально.
Но я добавлю нечто вроде ; echo %
, чтобы вывести имя файла на экран после завершения каждого запуска программы.
Я запустил эту команду:
ls -1 | xargs -I% -n1 -P8 myprogramm -s1 -r5 -q -o %.dat % ; echo %
Ошибок не наблюдаю, но вывод не соответствует тому, что я хотел.
После завершения всех запусков в bash я вижу только новую строку с одним символом, %
.
Но я хочу получить вывод, как:
file1
file2
file3
...
%
= fileN, является тем, что xargs запускает задания, как получить такой вывод?
Проверка интерпретирует ;
как разделитель команд даже до выполнения xargs
, поэтому сначала выполняется xargs
, а потом запускается echo %
.
Аргумент для xargs
– это команда для выполнения, а не список команд. Если вам нужно выполнить несколько команд, запишите их в скрипт и запустите его из xargs
.
Также разбор вывода ls
в основном неверен. Он не работает корректно для имен файлов, содержащих пробелы.
Как насчет:
ls -1 | xargs -I% -n1 -P8 bash -c 'echo now run: "$@"; echo myprogramm -s1 -r5 -q -o "$@".dat "$@"' _ %
Пример:
$ touch {1..5}
$ ls -1 | xargs -I% -n1 -P8 bash -c 'echo now run: "$@"; echo myprogramm -s1 -r5 -q -o "$@".dat "$@"' _ %
now run: 1
myprogramm -s1 -r5 -q -o 1.dat 1
now run: 2
myprogramm -s1 -r5 -q -o 2.dat 2
now run: 4
myprogramm -s1 -r5 -q -o 4.dat 4
now run: 3
myprogramm -s1 -r5 -q -o 3.dat 3
now run: 5
myprogramm -s1 -r5 -q -o 5.dat 5
Также можно убрать %
:
$ ls -1 | xargs -n1 -P8 bash -c 'echo now run: "$@"; echo myprogramm -s1 -r5 -q -o "$@".dat "$@"' _
now run: 1
myprogramm -s1 -r5 -q -o 1.dat 1
now run: 3
myprogramm -s1 -r5 -q -o 3.dat 3
now run: 4
myprogramm -s1 -r5 -q -o 4.dat 4
now run: 2
myprogramm -s1 -r5 -q -o 2.dat 2
now run: 5
myprogramm -s1 -r5 -q -o 5.dat 5
Уберите echo
перед myprogramm
, чтобы на самом деле запустить его.
Помните также:
Почему *не* разбирать `ls` (и что делать вместо этого)?.
Ответ или решение
Для решения задачи, обозначенной в вашем вопросе, давайте рассмотрим, как корректно использовать xargs
для одновременного запуска нескольких команд, а также как выводить имя обрабатываемого аргумента после завершения каждой команды.
Ключевая проблема в вашем исходном коде заключается в том, что вы пытались использовать ; echo %
, что не будет работать так, как вы ожидаете, поскольку ;
разделяет команды, и echo
выполняется сразу после xargs
, не ожидая завершения процессов. Чтобы правильно отобразить имена файлов после выполнения каждой команды, необходимо использовать другую конструкцию.
Вот исправленный пример команды:
ls -1 | xargs -I% -n1 -P8 bash -c 'myprogramm -s1 -r5 -q -o "%.dat" "%"; echo "Обработка завершена для файла: %"' _ %
Объяснение:
-
ls -1
: Эта команда создаст список файлов в текущем каталоге, каждый файл будет на новой строке. -
xargs -I% -n1 -P8
: Здесь мы используемxargs
с опцией-I%
, чтобы указать подстановочный символ%
, который будет заменен на каждую строку (имя файла) из входного потока. Опция-n1
говорит о том, что один аргумент передается в каждую команду, а-P8
указывает, что одновременно могут выполняться 8 процессов. -
bash -c
: Мы вызываем новый экземпляр оболочкиbash
, чтобы выполнить последовательность команд. -
myprogramm -s1 -r5 -q -o "%.dat" "%"
: Здесь вы выполняете вашу программуmyprogramm
, передавая необходимые параметры. Вместо%
в имя выходного файла подставляется имя текущего файла, обрабатываемого в данный момент. -
echo "Обработка завершена для файла: %"
: После завершения выполнения команды выводится сообщение с информацией о том, какой файл был обработан, используя тот же подстановочный символ%
.
Учтите:
- Избегайте парсинга вывода
ls
, особенно если имена файлов могут содержать пробелы или специальные символы. Вместо этого, по возможности, используйте его в сочетании сfind
для обработки сложных имен файлов.
Пример:
Предположим, что у вас есть 5 файлов:
$ touch file1 file2 file3 file4 file5
$ ls -1 | xargs -I% -n1 -P8 bash -c 'myprogramm -s1 -r5 -q -o "%.dat" "%"; echo "Обработка завершена для файла: %"' _ %
Вывод будет примерно следующим:
Обработка завершена для файла: file1
Обработка завершена для файла: file2
...
Это позволит вам получить вывод об обработке каждого файла в реальном времени, как вы и планировали.