Запускает произвольную команду, и, только если она завершилась успешно, копирует её stdout в системный буфер обмена — на macOS, Linux (X11 и Wayland) и Windows.
$ xcopy git rev-parse HEAD
Successfully copied to the clipboard!
$ pbpaste # macOS
a1b2c3d4e5f6...
Стандартный паттерн command | pbcopy копирует в буфер обмена всё,
что успел вывести процесс, даже если он упал с ошибкой на середине —
в буфере остаётся оборванный/мусорный результат. xcopy сначала
полностью считывает вывод команды в собственный буфер, проверяет код
завершения, и только при успехе (exit code == 0) передаёт
накопленные данные в буфер обмена. Если команда завершилась с
ошибкой — буфер обмена не трогается вообще.
Зависимости для сборки: компилятор с поддержкой C99 и POSIX
(popen, system, sys/wait.h).
cc -std=c99 -O2 -o xcopy xcopy.c
sudo install -m 755 xcopy /usr/local/bin/xcopyxcopy сам ничего не реализует для доступа к буферу обмена — он
вызывает внешнюю системную утилиту. Какая именно утилита доступна —
определяется на этапе компиляции через препроцессор (#if defined(__APPLE__),
#elif defined(__linux__), #elif defined(__CYGWIN__) || defined(_WIN32)),
то есть бинарник, собранный под Linux, никогда даже не будет
содержать код для pbcopy, и наоборот.
Для Linux заранее нельзя определить компиляцией, что стоит в
системе — X11, Wayland или ничего, поэтому там подключается список
кандидатов, и на этапе выполнения используется первый найденный в
$PATH:
| ОС | Утилита(ы) | Нужно установить отдельно |
|---|---|---|
| macOS | pbcopy |
нет, есть из коробки |
| Linux (Wayland) | wl-copy |
пакет wl-clipboard |
| Linux (X11) | xclip → иначе xsel |
xclip или xsel |
| Windows (Cygwin/MSYS) | clip |
нет, есть из коробки |
Если на Linux не установлена ни одна из подходящих утилит, xcopy
завершится с понятной ошибкой и подскажет, что именно попробовал:
$ xcopy echo hi
Error: no clipboard utility found on this Linux system.
Tried: wl-copy, xclip, xsel
Попытка собрать xcopy на платформе, для которой в коде вообще нет
секции препроцессора (не macOS/Linux/Windows), закончится ошибкой
компиляции (#error), а не тихим падением в рантайме.
xcopy <команда> [аргументы...]
Все аргументы после xcopy склеиваются в одну строку через пробел и
выполняются как есть через sh -c, точно так же, как если бы вы
написали их в шелле напрямую. Это значит, что пайпы, редиректы и
кавычки внутри команды работают привычным образом — но и требуют
той же осторожности, что и обычный sh -c (см. «Безопасность» ниже).
Скопировать текущий git-хэш:
xcopy git rev-parse HEADСкопировать содержимое файла:
xcopy cat notes.txtСкопировать результат сложного пайплайна (нужны кавычки, так как
| и && иначе разберёт по частям сам ваш внешний шелл, а не xcopy):
xcopy "ps aux | grep nginx"Скопировать вывод команды вместе со stderr (git, например, часть
сообщений всегда пишет в stderr, а не в stdout):
xcopy "git pull 2>&1"- Аргументы склеиваются в одну командную строку и запускаются через
popen(cmd, "r"). - Весь stdout команды построчно читается в динамически растущий буфер в памяти (без ограничения на размер вывода).
pclose()возвращает код завершения команды. Если код не нулевой или процесс был завершён сигналом — программа печатает диагностику в stderr и не трогает буфер обмена.- Только если команда завершилась успешно, определяется доступная
в системе утилита буфера обмена (см. таблицу выше), и накопленный
буфер целиком (
fwriteпо точной длине, а не поstrlen, поэтому бинарные данные с нулевыми байтами не обрезаются) передаётся ей на вход.
| Код | Значение |
|---|---|
| 0 | Команда выполнена успешно, вывод скопирован в буфер |
| 1 | Неверные аргументы, ошибка запуска команды, сама команда завершилась с ненулевым кодом/по сигналу, отсутствует подходящая утилита буфера обмена, либо ошибка копирования |
Диагностика во всех случаях ошибки печатается в stderr, а не в stdout, поэтому вывод самой оборачиваемой команды остаётся «чистым» для дальнейшего использования в пайпах.
Команда выполняется через sh -c, как и в любом инструменте на базе
popen/system. Не передавайте в xcopy непроверенный пользовательский
ввод в качестве аргументов — как и с обычным шеллом, туда можно
подставить ;, `, $(...) и получить выполнение произвольного кода.