xargs for Windows
This is a basic implementation of xargs and may be used freely with Windows OS. This version of xargs may not contain some of the more advanced features that the regular xargs for Linux has, and again, it is just a basic implementation.
Install
- Copy «xargs.bat» into one of your PATH folders.
- Done. Re-open your terminal if it is open, and you may now use it.
Where or What is a PATH Folder?
If you are unsure, go ahead and copy it into one of these directories: «C:\Windows\system32» or «C:\Windows»
As far as what that is. Spend some time watching tutorials or researching to help learn.
Example of Correct Usage
Ping 1.1.1.1 by piping the output of the «echo» command
WRONG USAGE and will not work (default from Windows)
echo: 1.1.1.1 | ping
RIGHT USAGE and will work (with xargs installed)
echo: 1.1.1.1 | xargs ping
Video Tutorial
▍ Введение
Одним из наиболее неприятных моментов в работе с оболочкой UNIX является невозможность легко запланировать несколько параллельных задач, которые бы полностью использовали ядра процессора, представленные в большинстве современных системах. В данной статье в качестве примера рассматривается сжатие файлов, но проблема также возникает и при выполнении многих задач с интенсивными вычислениями, таких как: обработка изображений/аудио/медиа, подбор паролей и анализ хэшей, резервное копирование, а также извлечение, преобразование и загрузка баз данных. Вполне понятно, что ждать, когда gzip * выполнится на одном ядре процессора, довольно утомительно, в то время как большая часть вычислительной мощности машины простаивает.
Это можно объяснить несовершенством первого десятилетия Research UNIX, который не разрабатывался на машинах с SMP. Оболочка Bourne не вышла из 7-го издания с каким-либо собственным синтаксисом или средствами управления для последовательного управления потреблением ресурсов фоновыми процессами.
Для реализации некоторых из этих функций были бессистемно разработаны соответствующие утилиты. GNU-версия xargs способна осуществлять некоторый примитивный контроль над распределением фоновых процессов, что довольно подробно обсуждается в документации. Хотя расширения GNU для xargs распространились на многие другие реализации (в частности, BusyBox, включая выпуск для Microsoft Windows, пример ниже), они не соответствуют POSIX.2 и, скорее всего, не найдут применения в коммерческих UNIX системах.
Бывалые пользователи xargs помнят его как полезный инструмент для каталогов, содержащих слишком много файлов, чтобы можно было использовать echo * или другие шаблоны поиска; в такой ситуации xargs вызывается для многократной пакетной обработки групп файлов одной командой. По мере развития xargs за пределами POSIX, он приобрёл новую актуальность, которую будет полезно изучить.
▍ Почему POSIX.2 настолько плох?
Для ясного понимания отсутствия согласованного планирования задач в UNIX необходимо немного углубиться в историю развития этих утилит.
Оболочка, как определено в POSIX.2, имеет примитивные функции управления системными заданиями. Эта функциональность возникла из одного источника — csh, написанного Биллом Джоем и впервые распространённого в 1978 году, и с тех пор не получила значительного развития, даже после того, как управление заданиями было поглощено оболочкой Korn. Ниже приведён пример управления заданиями [c]sh, реализованный в bash, которым оболочки POSIX.2 по-прежнему ограничены. В этом сеансе ^Z и ^C означают комбинацию клавиш Control.
$ xz -9e users00.dat
^Z
[1]+ Stopped xz -9e users00.dat
$ bg
[1]+ xz -9e users00.dat &
$ xz -9e users01.dat
^Z
[2]+ Stopped xz -9e users01.dat
$ xz -9e users02.dat
^Z
[3]+ Stopped xz -9e users02.dat
$ jobs
[1] Running xz -9e users00.dat &
[2]- Stopped xz -9e users01.dat
[3]+ Stopped xz -9e users02.dat
$ bg 3
[3]+ xz -9e users02.dat &
$ jobs
[1] Running xz -9e users00.dat &
[2]+ Stopped xz -9e users01.dat
[3]- Running xz -9e users02.dat &
$ fg 2
xz -9e users01.dat
^C
$ jobs
[1]- Running xz -9e users00.dat &
[3]+ Running xz -9e users02.dat &
В приведённом выше примере были запущены три команды сжатия, вторая отменена, а остальные перенесены в фоновый режим.
В качестве стимула для дальнейшего обсуждения приведём неполный список очевидных недостатков этой конструкции:
- Отсутствует какая-либо журнализация и распределение доступных ресурсов процессора для выполнения заданий по мере поступления ресурсов.
- Неудачные команды, которые возвращают ненулевой статус выхода или завершаются ненормально, не передаются должным образом. Было бы весьма полезно помещать такие случаи в очередь неудач для попытки повторного выполнения.
- Отсутствует глобальное системное планирование заданий. Любой пользователь может выполнять фоновые задания, которые могут чрезмерно перегрузить машину как самостоятельно, так и совместно с другими пользователями.
Хотя SMP впервые появилась в компьютерных системах, продаваемых на рынке в 1962 году, и прочно закрепилась с выпуском IBM System/370, который появился в том же году, что и рождение UNIX, такие мощные машины не были доступны разработчикам в «условиях бедности» того времени, которое известно как Research UNIX. Системы с такими возможностями не получат широкого распространения ещё много лет.
«[Система] UNIX не поддерживала многопроцессорность… Процессор IBM 3033AP отвечал этому требованию, обладая примерно в 15 раз большей вычислительной мощностью, чем один процессор PDP-11/70.»
Похоже, что первой платформой UNIX с поддержкой SMP был Sperry/UNIVAC 1100, внутренний порт AT&T, начатый в 1977 году. Этот порт, как и более поздние усилия IBM на System/370, оба были построены на компонентах ОС, предоставленных поставщиками (EXEC 8 и TSS), и, похоже, не полагались на общую SMP, реализованную в ядре 7-й редакции.
«Любая конфигурация, поставляемая Sperry, включая многопроцессорные, может запускать систему UNIX».
Поскольку csh не мог быть написан на многопроцессорной машине, а прошедшие годы до появления UNIX System V в целом не ввели SMP, контроль заданий оболочки также не имеет представления о нескольких процессорах и не был разработан для их использования.
Такое отсутствие прогресса было закреплено в POSIX.2 из-за войн UNIX, где эти стандарты были выпущены в качестве защитной меры консорциумом во главе с IBM, HP и DEC (среди прочих), навсегда заблокировав возможности UNIX System V в индустрии. Для многих инновации за пределами POSIX оказались недопустимыми.
Когда POSIX.2 был утверждён, все основные игроки реализовали SMP, но не было мотива расширить стандартную оболочку POSIX.2 за пределы System V. Это привело к тому, что серверы x86 NUMA и встроенные big.LITTLE были одинаково слабо представлены в любой строго соответствующей POSIX-имплементации.
Причина, по которой параллельный вывод процессов gzip остаётся нетривиальной задачей, кроется в кодифицированном защитном маркетинге.
▍ GNU xargs
В связи с отсутствием современного управления заданиями в оболочке POSIX.2, можно воспользоваться одним хаком, который предоставляет расширенные возможности в GNU xargs. Другие решения включают GNU parallel и pdsh, которые здесь не представлены.
Классическая утилита xargs объединяет стандартный ввод и позиционные параметры для форка команд. Простым примером xargs может быть перечисление нескольких номеров inode:
$ echo /etc/passwd /etc/group | xargs stat -c '%i %n'
525008 /etc/passwd
525256 /etc/group
Этот базовый вызов невероятно полезен при работе с большим количеством файлов, превышающим максимальный размер командной строки оболочки. Ниже приведён пример из древней коммерческой UNIX, где xargs используется для решения проблемы нехватки памяти в оболочке:
$ uname -a
HP-UX localhost B.10.20 A 9000/800 862741461 two-user license
$ cd /directory/with/lots/of/files
$ chmod 644 *
sh: There is not enough memory available now.
$ ls | xargs chmod 644
$ echo *
sh: There is not enough memory available now.
$ ksh
$ what /usr/bin/ksh | grep Version
Version 11/16/88
$ echo *
ksh: no space
$ /usr/dt/bin/dtksh
$ echo ${.sh.version}
Version M-12/28/93d
$ echo *
Pid 1954 received a SIGSEGV for stack growth failure.
Possible causes: insufficient memory or swap space,
or stack size exceeded maxssiz.
Memory fault
$ /usr/old/bin/sh
$ ls *
/usr/bin/ls: arg list too long
$ ls * *
no stack space
Удачи найти это в руководстве…
Существует проблема с POSIX xargs, которая заключается в том, что он плохо справляется с пробелами или новыми строками в файлах на стандартном вводе. Единственный универсально запрещённый символ в имени файла UNIX — это прямая косая черта (/). Расширение GNU, аргумент -0, устанавливает разделитель файлов на NUL, или нулевой байт, что значительно упрощает обработку файлов и значительно повышает безопасность. GNU find имеет переключатели для использования этой возможности в конвейере (pipeline). В действительности, xargs, в котором нет -0, просто не стоит использовать.
Второе крупное расширение GNU позволяет выполнять параллельную обработку с помощью аргумента -P #. Сам по себе он не запускает параллельную обработку, но в сочетании с опцией -L 1 все входные файлы будут запускаться отдельно с целевой программой, выполняя только отведённое количество слотов процесса.
Перед запуском нашего первого параллельного скрипта проверьте программу, которая сообщает о количестве ядер процессора, видимых Linux:
$ nproc
4
Это число может не совпадать с числом физических ядер, а также SMT/гиперпотоков, которые могут быть реализованы в нескольких ядрах. Некоторые команды плохо работают при выполнении в потоках, реализованных на одном ядре.
Теперь представим параллельный скрипт сжатия, достаточно гибкий для генерации нескольких форматов файлов. Он совместим с POSIX и работает под управлением Debian DASH и оболочки BusyBox.
$ cat ~/ppack_lz
#!/bin/sh
PARALLEL="$(nproc --ignore=1)"
EXT="${0##*_}"
case "$EXT" in
bz2) CMD='bzip2 -9' ;;
gz) CMD='gzip -9' ;;
lz) CMD='lzip -9' ;;
xz) CMD='xz -9e' ;;
zst) CMD='zstd --rm --single-thread --ultra -22' ;;
esac
if [ -z "$1" ]
then echo "Specify files to pack into ${EXT} files."
else for x
do printf '%s\0' "$x"
done | nice xargs -0 -L 1 -P "$PARALLEL" $CMD
fi
Несколько примечаний к этому примеру:
- Скрипт настроен на использование всех процессоров, о которых сообщает nproc, кроме одного. В зависимости от загрузки машины, возможно, лучше установить это значение вручную.
- Скрипт определяет тип сжатия по последним символам после подчёркивания (_) в имени файла скрипта. Если скрипт назван foo_bz2, то он будет выполнять обработку bzip2 вместо lzip, выбранного выше с помощью ppack_lz.
- Файлы для сжатия, указанные в качестве аргументов скрипта, будут выдаваться циклом for на стандартный вывод, разделённый NUL, для планирования xargs.
Чтобы наблюдать этот сценарий в действии, полезно иметь (практически POSIX-совместимую) функцию оболочки для поиска вывода команды ps:
psearch () {
local xx_a xx_b xx_COLUMNS IFS=\|
[ -z "$COLUMNS" ] && xx_COLUMNS=80 || xx_COLUMNS="$COLUMNS"
ps -e -o user:7,pid:5,ppid:5,start,bsdtime,%cpu,%mem,args |
while read xx_a
do if [ -z "$xx_b" ]
then printf '%s\n' "${xx_b:=$xx_a}"
else for xx_b
do case "$xx_a" in
*"$xx_b"*)
printf '%s\n' "$(expr substr "$xx_a" 1 "$xx_COLUMNS")" ;;
esac
done
fi
done
}
С готовым монитором мы можем запустить этот скрипт для нескольких WAV-файлов на четырёхъядерном процессоре:
$ ~/ppack_lz *.wav
В другом терминале виден xargs, который планирует выполнение этих команд:
$ psearch lzip
USER PID PPID STARTED TIME %CPU %MEM COMMAND
cfisher 29995 29992 16:01:49 0:00 0.0 0.0 xargs -0 -L 1 -P 3 lzip -9
cfisher 30007 29995 16:02:10 0:27 100 2.8 lzip -9 track01.cdda.wav
cfisher 30046 29995 16:02:31 0:05 97.5 1.4 lzip -9 track02.cdda.wav
cfisher 30049 29995 16:02:33 0:04 108 1.2 lzip -9 track03.cdda.wav
Как указано в документации по параллелизму xargs, отправка SIGUSER1 и SIGUSER2 будет противоположно добавлять и уменьшать количество параллельных процессов, запланированных xargs. Добавление вступает в силу немедленно, в то время как уменьшение будет требовать завершения существующих процессов.
Приведённая выше форма команды xargs является ограничивающей, поскольку порядок заданных аргументов и параметр, предоставляемый xargs, не могут быть изменены. Более тонкий вариант, обеспечивающий большую гибкость сценариев, можно задать с помощью опции POSIX -I, но для этого требуется «мета-скрипт», который генерируется во время выполнения.
$ cat ~/parallel-pack_gz
#!/bin/sh
PARALLEL="$(nproc --ignore=1)"
S="$(mktemp -t PARALLEL-XXXXXX)"
trap 'rm -f "$S"' EXIT
EXT="${0##*_}"
case "$EXT" in
7z) printf '#!/bin/sh \n exec 7za a -bso0 -bsp0 --mx=9 "${1}.7z" "$1"' ;;
bz2) printf '#!/bin/sh \n exec bzip2 -9 "$1"' ;;
gz) printf '#!/bin/sh \n exec gzip -9 "$1"' ;;
lz) printf '#!/bin/sh \n exec lzip -9 "$1"' ;;
xz) printf '#!/bin/sh \n exec xz -9e "$1"' ;;
zst) printf '#!/bin/sh\nexec zstd --rm --single-thread --ultra -22 "$1"';;
esac > "$S"
chmod 500 "$S"
if [ -z "$1" ]
then echo "Specify files to pack into ${EXT} files."
else for x
do printf '%s\0' "$x"
done | nice xargs -0 -P "$PARALLEL" -Ifname "$S" fname
fi
Выше был добавлен вызов 7za, который содержится в пакете p7zip, доступном на многих платформах (пользователи Red Hat могут найти его в EPEL). Использование 7-zip сопровождается несколькими предостережениями, поскольку сама программа является многопоточной (использует от 1,25 до 1,5 ядер) и требования к памяти повышаются, поэтому количество параллельных процессов должно быть уменьшено. Кроме того, 7-zip имеет возможность добавлять существующий архив (как Info-ZIP, который он призван заменить); не планируйте несколько процессов 7-zip для добавления в один и тот же целевой файл. Возможности шифрования в 7-zip могут представлять особый интерес во избежание нарушений правил безопасности при работе с резервными носителями.
Хотя название этой статьи, «параллельные оболочки» — технически верное (в вышеупомянутом использовании), приведённый выше exec стирает оболочки мгновенно и является более эффективным использованием таблицы процессов.
С помощью этого гибкого скрипта мы проводим стресс-тест с pigz, многопоточным gzip, против 80 файлов размером 2 гигабайта (которые в данном случае являются файлами данных базы данных Oracle, содержащими блоки таблиц и индексов в случайном порядке). Базовым сервером является (старый) HP DL380 Gen8 с 8 доступными процессорными ядрами:
$ lscpu | grep name
Model name: Intel(R) Xeon(R) CPU E5-2609 0 @ 2.40GHz
# time pigz -9v users*
users00.dat to users00.dat.gz
users01.dat to users01.dat.gz
users02.dat to users02.dat.gz
...
users77.dat to users77.dat.gz
users78.dat to users78.dat.gz
users79.dat to users79.dat.gz
real 45m51.904s
user 335m15.939s
sys 2m11.146s
Во время выполнения pigz утилита top сообщает о следующей загрузке процессора процесса:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11162 root 20 0 617616 6864 772 S 714.2 0.0 17:58.21 pigz -9v users01.dat...
По сравнению с этим (идеальным) бенчмарком, сценарий xargs был немного быстрее, даже работая под приоритетом nice для CPU и с PARALLEL, установленным на 8 на том же хосте:
$ time ~/parallel-pack_gz users*
real 44m42.107s
user 341m18.650s
sys 2m47.379s
Во время выполнения xargs-orchestrated параллельно gzip в верхнем отчёте были перечислены все однопоточные процессы, запланированные на отдельных процессорах (обратите внимание на уровень приоритета 30, уменьшенный до nice, по сравнению с 20 для pigz):
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14624 root 30 10 4624 828 424 R 100.0 0.0 0:09.85 gzip -9 users00.dat
14625 root 30 10 4624 832 424 R 100.0 0.0 0:09.86 gzip -9 users01.dat
...
14630 root 30 10 4624 832 424 R 99.3 0.0 0:09.76 gzip -9 users06.dat
14631 root 30 10 4624 824 424 R 98.0 0.0 0:09.69 gzip -9 users07.dat
В этом идеальном варианте количество файлов равномерно делилось на количество процессоров, что помогло параллельному xargs победить pigz; добавление ещё одного файла привело бы к проигрышу xargs в этой гонке.
Существуют также параллельные версии bzip2 (pbzip2), lzip (plzip), xz (pixz), а утилита zstd обычно является многопоточной и использует все ядра процессора, но это значение по умолчанию было отключено выше. Многопоточные версии могут демонстрировать отличные от xargs характеристики производительности. Для 7za, xargs является очевидным методом утилизации всей вычислительной мощности системы.
Существенной проблемой ввода-вывода при параллельном планировании xargs на вращающихся носителях является фрагментация. Хотя на твердотельных накопителях это не является фактором, на обычных носителях это проблема, которую следует регулярно решать, если это возможно, что можно наблюдать на примере этого результата, сопоставленного по номеру инода (inod):
# ls -li users46.dat.lz
2684590096 -rw-r--r--. 1 oracle dba 174653599 Jan 28 13:30 users46.dat.lz
# xfs_fsr -v
...
ino=2684590096
extents before:52 after:1 DONE ino=2684590096
...
Эта фрагментация в файловой системе XFS (родной для Red Hat и производных) очевидна. С ней следует регулярно бороться в тех файловых системах, где существуют инструменты для её устранения (например, e4defrag, btrfs defrag). На файловой системе ZFS, где не существует инструментов для устранения фрагментации, к параллельной обработке следует подходить с большой осторожностью и только для тех наборов данных, которые находятся в пулах с достаточным свободным пространством.
Из-за проблемы с фрагментацией нам лучше отказаться от параллельной распаковки, и предпочесть однопоточный подход, не зависящий от сжатия:
$ cat unpack
#!/bin/sh
for x
do echo "$x"
EXT="${x##*.}"
case "$EXT" in
bz2) bzip2 -cd "$x" ;;
gz) gzip -cd "$x" ;;
lz) lzip -cd "$x" ;;
xz) xz -cd "$x" ;;
zst) zstd -cd "$x" ;;
esac > "$(basename "$x" ".${EXT}")"
done
Наконец, эта техника может быть использована в порте BusyBox для Windows и, вероятно, в других (POSIX) реализациях оболочки на платформе Win32/64, поддерживающих GNU xargs. В оболочке BusyBox не реализован nice (удалите его из скрипта), также в ней не предусмотрен nproc (установите PARALLEL вручную). BusyBox полностью реализует только gzip и bzip2 (апплет xz существует, но не реализует числовую настройку качества). Что касается изменений bzip2, вот демонстрация на моём ноутбуке, тест с копией всех файлов Cygwin .DLL:
C:\Temp>busybox64 sh
C:/Temp $ time sh parallel-pack_bz2 dtest/*.dll
real 0m 58.70s
user 0m 0.00s
sys 0m 0.06s
C:/Temp $ exit
C:\Temp>dir dtest
Volume in drive C is OSDisk
Volume Serial Number is E44B-22EC
Directory of C:\Temp\dtest
02/02/2021 11:10 AM <DIR> .
02/02/2021 11:10 AM <DIR> ..
02/02/2021 11:09 AM 40,957 cygaa-1.dll.bz2
02/02/2021 11:09 AM 263,248 cygakonadi-calendar-4.dll.bz2
02/02/2021 11:09 AM 289,716 cygakonadi-contact-4.dll.bz2
. . .
02/02/2021 11:10 AM 658,119 libtcl8.6.dll.bz2
02/02/2021 11:10 AM 489,135 libtk8.6.dll.bz2
02/02/2021 11:09 AM 5,942 Xdummy.dll.bz2
1044 File(s) 338,341,460 bytes
2 Dir(s) 133,704,908,800 bytes free
▍ Заключение
IBM в процессе переноса UNIX на System/370 написала:
UNIX… является единственной доступной операционной системой, которая работает на всех компьютерах — от однокристальных микрокомпьютеров до крупнейших мэйнфреймов общего назначения… Это представляет собой, по крайней мере, два порядка величины в диапазоне мощности и производительности… Способность системы UNIX изящно преодолевать диапазон от микрокомпьютеров до высокопроизводительных мэйнфреймов — это заслуга её первоначального дизайна, разработанного более десяти лет назад, и её продуманной эволюции.
В то же время мы испытываем ностальгию по непонятному нам управлению заданиями (в операционных системах System/370).
Хотя Linux, возможно, не дотягивает до уровня PDP-11, он в значительной степени разделяет это свойство с 7-м изданием, работая при этом на машинах с невообразимой скоростью с точки зрения 1970-х годов. Однако POSIX.2 требует, чтобы мы оставались в 1970-х годах с рядом наших инструментов, что, вероятно, толкает пользователей к менее экспансивным конкурентам с лучшим (в плане работы с задачами) инструментарием.
Я начал своё знакомство с UNIX SMP на Encore Multimax в университете в начале 90-х годов, и мне трудно представить, что даже пользовательское пространство этой машины будет ограничено неразумными требованиями POSIX.2. Принятие, даже сейчас, тех же ограничений для современных SMP конструкций является, в некоторой степени, проклятием.
POSIX во многих сферах считается незыблемым стандартом. То, что SELinux и systemd в малой степени превзошли его, даёт некоторую надежду на то, что мы сможем преодолеть ограничения, наложенные на нас предыдущим поколением. Возможно, очевидным решением было бы использование systemd в качестве новой системы планирования заданий. Хотя можно утверждать, что портативность (portability) преобладает над функциональностью, инновации также должны в конечном счёте преобладать над традициями. Портативность — полезное стремление, но возможности и эффективность также не лишены ценности.
Участие ядра в улучшенной системе планирования заданий не является строго необходимым условием. Базовая реализация в пространстве пользователя, добавленная к POSIX, скорее всего, будет встречена с большим удовольствием сообществом пользователей (и, надеюсь, будет лучше, чем использование SIGUSR1/2 для корректировки во время выполнения). Стандарт POSIX не позволяет этого, но пришло время оставить прошлое позади.
Быть вынужденным пользоваться непонятной утилитой для параллельного написания сценариев из-за ранней бедности UNIX — неразумная позиция. Обновлённый стандарт POSIX.2 для функциональной оболочки и различных пользовательских утилит давно назрел.
А пока этого не произошло, благодарите FSF за подобный подход.
xargs is a Linux utility that allows you to build command from the standard input.
xargs –help
Usage: xargs [OPTION]… COMMAND [INITIAL-ARGS]…
Run COMMAND with arguments INITIAL-ARGS and more arguments read from input.Mandatory and optional arguments to long options are also
mandatory or optional for the corresponding short option.
-0, –null items are separated by a null, not whitespace;
disables quote and backslash processing and
logical EOF processing
-a, –arg-file=FILE read arguments from FILE, not standard input
-d, –delimiter=CHARACTER items in input stream are separated by CHARACTER,
not by whitespace; disables quote and backslash
processing and logical EOF processing
-E END set logical EOF string; if END occurs as a line
of input, the rest of the input is ignored
(ignored if -0 or -d was specified)
-e, –eof[=END] equivalent to -E END if END is specified;
otherwise, there is no end-of-file string
-I R same as –replace=R
-i, –replace[=R] replace R in INITIAL-ARGS with names read
from standard input; if R is unspecified,
assume {}
-L, –max-lines=MAX-LINES use at most MAX-LINES non-blank input lines per
command line
-l[MAX-LINES] similar to -L but defaults to at most one non-
blank input line if MAX-LINES is not specified
-n, –max-args=MAX-ARGS use at most MAX-ARGS arguments per command line
-o, –open-tty Reopen stdin as /dev/tty in the child process
before executing the command; useful to run an
interactive application.
-P, –max-procs=MAX-PROCS run at most MAX-PROCS processes at a time
-p, –interactive prompt before running commands
–process-slot-var=VAR set environment variable VAR in child processes
-r, –no-run-if-empty if there are no arguments, then do not run COMMAND;
if this option is not given, COMMAND will be
run at least once
-s, –max-chars=MAX-CHARS limit length of command line to MAX-CHARS
–show-limits show limits on command-line length
-t, –verbose print commands before executing them
-x, –exit exit if the size (see -s) is exceeded
–help display this help and exit
–version output version information and exit
I wanted to delete all local branches except the develop branch and I typed in:
$ git branch | grep -v "develop" | xargs git branch -D 'xargs' is not recognized as an internal or external command, operable program or batch file.
Windows xargs reading from STDIN
Apparently, the xargs is not found on windows command shell, and we can quickly implement a xargs-like batch utility like this:
@echo off
:: example: git branch | grep -v "develop" | xargs git branch -D
:: https://helloacm.com/simple-xargs-batch-implementation-for-windows/
setlocal
set args=%1
shift
:start
if [%1] == [] goto start1
set args=%args% %1
shift
goto start
:start1
for /F "tokens=*" %%a in ('more') do (
%args% %%a
)
And here we go… except there is a tiny error which can be safely dis-regarded. The idea is to first shift all command line parameters and concatenate them into a single variable %args%, then using a for utility, we can simulate and obtain each line from the STDIN, then finally build and execute command in the form of %args %%a
Please note that the set /p does not work with pipeline and that is why we use the more together with for /F “tokens=*” to achieve the similar tasks.
git-branch-delete-using-xargs
Windows xargs reading from File
The xargs supports reading from the file instead of the Standard Input (STDIN). We can improve the above xargs batch script by checking if the first argument is -a followed by the text file as input. Example usage:
xargs -a input.txt echo
The input.txt contains three lines:
1 2 3
So the above xargs will be equivalent to the below after building the commands:
echo 1 echo 2 echo 3
We use the setlocal enabledelayedexpansion to set the correct source for the for /f – either the ‘more’ command or the text file:
@echo off
:: example: git branch | grep -v "develop" | xargs git branch -D
:: example xargs -a input.txt echo
:: https://helloacm.com/simple-xargs-batch-implementation-for-windows/
setlocal enabledelayedexpansion
set args=
set file='more'
:: read from file
if "%1" == "-a" (
if "%2" == "" (
echo Correct Usage: %0 -a Input.txt command
goto end
)
set file=%2
shift
shift
goto start
)
:: read from stdin
set args=%1
shift
:start
if [%1] == [] goto start1
set args=%args% %1
shift
goto start
:start1
for /F "tokens=*" %%a in (!file!) do (
%args% %%a
)
:end
xargs is now open source: https://github.com/DoctorLai/BatchUtils/blob/master/xargs.cmd
–EOF (The Ultimate Computing & Technology Blog) —
GD Star Rating
loading…
907 words
Last Post: How to Show/Execute History Command Lines in Windows Command Line Prompt?
Next Post: Binary Search to Guess Number Game (C++ Coding Exercise)
Sometimes, we have to use the Microsoft Windows cmd.exe command line. Maybe it’s at a client site or on a user machine where installing PowerShell, Cygwin or Mingw isn’t appropriate. Maybe you’re on a domain member so locked down by group policy you can’t do anything if you want to. Either way, you have to use cmd.exe, and you’re swearing.
I find out about the odd useful command that makes the Windows shell more usable, and I’ll be trying to post them here. The first is forfiles, a basic alternative to find -exec or find|xargs.
If you’re missing find -exec (or xargs) it turns out that Windows provides forfiles to do a limited subset of the work that find -exec can do. This’ll help with simple jobs like flattening out a deep directory tree into a flat folder of files, running a command recursively on every file in a directory, etc.
For example, here’s how to find every TrueType font file within the deep directory tree C:\deeptree and copy the files to C:\flat.
forfiles /s /p C:\deeptree /M *.ttf /c "cmd /c move @file C:\flat"
You really want to use an absolute path when you invoke move here, as it’s invoked with the file’s parent directory as its cwd, not the directory you ran the findfiles command in. Use a relative path and you’ll just land up renaming all your files — which is a handy trick, but not what you intended.
In reality you’ll also want to use more appropriate paths than folders off the root of C:\ . Beware spaces in pathnames, and remember that Windows has totally different rules to *nix in this area.
This particular case can be just as easily accomplished by doing a search for *.ttf from the parent directory, selecting all, copying, and pasting into an empty directory. More complex uses of this command like recursive renames or command invocations, not so much.
See forfiles /? for help.
What’s xargs?
Quotexargs (short for «extended arguments» [1]) is a command on Unix and most Unix-like operating systems used to build and execute commands from standard input. It converts input from standard input into arguments to a command.
Some commands such as grep and awk can take input either as command-line arguments or from the standard input. However, others such as cp and echo can only take input as arguments, which is why xargs is necessary.
https://en.wikipedia.org/wiki/Xargs
Windows xargs clone: PPX2
https://github.com/ghuls/ppx2
Some examples of usage :
Calculating the MD5 hash of a group of files under a folder :
dir /b /s /a-d D:\Folder | ppx2.exe -L 1 md5sum.exe "{}" > md5.txt
.mpg convertion :
dir /b *.mpg | ppx2 -P 4 -L 1 ffmpeg.exe -i "{}" -quality:v 1 "{}.mp4"
Attached is the project built with PellesC v11
