xcp is a (partial) clone of the Unix cp command. It is not intended as a full replacement

Overview

xcp: An extended cp

xcp is a (partial) clone of the Unix cp command. It is not intended as a full replacement, but as a companion utility with some more user-friendly feedback and some optimisations that make sense under certain tasks (see below).

Crates.io CircleCI OSX Build Status

Warning: xcp is currently beta-level software and almost certainly contains bugs and unexpected or inconsistent behaviour. It probably shouldn't be used for anything critical yet.

Installation

NOTE: xcp requires Rust 1.36 or higher.

Cargo

xcp can be installed directly from crates.io with:

cargo install xcp

Arch Linux

xcp is available on the Arch Linux User Repository. If you use an AUR helper, you can execute a command such as this:

yay -S xcp

Features and Anti-Features

Features

  • Displays a progress-bar, both for directory and single file copies. This can be disabled with --no-progress.
  • On Linux it uses copy_file_range call to copy files. This is the most efficient method of file-copying under Linux; in particular it is filesystem-aware, and can massively speed-up copies on network mounts by performing the copy operations server-side. However, unlike copy_file_range sparse files are detected and handled appropriately.
  • Optimised for 'modern' systems (i.e. multiple cores, copious RAM, and solid-state disks, especially ones connected into the main system bus, e.g. NVMe).
  • Optional aggressive parallelism for systems with parallel IO. Quick experiments on a modern laptop suggest there may be benefits to parallel copies on NVMe disks. This is obviously highly system-dependent.
  • Switchable 'drivers' to facilitate experimenting with alternative strategies for copy optimisation. Currently 2 drivers are available:
    • 'parfile': the previous hard-coded xcp copy method, which parallelises tree-walking and per-file copying. This is the default.
    • 'parblock': An experimental driver that parallelises copying at the block level. This has the potential for performance improvements in some architectures, but increases complexity. Currently MacOS is not supported. Testing is welcome.
  • Non-Linux Unix-like OSs (OS X, *BSD) are supported via fall-back operation (although sparse-files are not yet supported in this case).
  • Optionally understands .gitignore files to limit the copied directories.
  • Optional native file-globbing.

(Possible) future features

  • Conversion of files to sparse where appropriate, as with cp's --sparse=always flag.
  • Aggressive sparseness detection with lseek.

Anti-Features

  • On Linux copy_file_range() requires a kernel version of 4.5 and onwards; if it is missing xcp will fall-back to user-space copy.
  • On non-Linux OSs sparse-files are not supported (although could be added if supported by the OS).
  • Assumes a 'modern' system with lots of RAM and fast, solid-state disks. In particular it is likely to thrash on spinning disks as it attempts to gather metadata and perform copies at the same time.
  • Currently missing a lot of cp's features and flags, although these could be added.

Performance

Benchmarks are mostly meaningless, but to check we're not introducing too much overhead for local copies, the following are results from a laptop with an NVMe disk and in single-user mode. The target copy directory is a git checkout of the Firefox codebase, having been recently gc'd (i.e. a single 4.1GB pack file). fstrim -va is run before each test run to minimise SSD allocation performance interference.

Local copy

  • Single 4.1GB file copy, with the kernel cache dropped each run:
    • cp: ~6.2s
    • xcp: ~4.2s
  • Single 4.1GB file copy, warmed cache (3 runs each):
    • cp: ~1.85s
    • xcp: ~1.7s
  • Directory copy, kernel cache dropped each run:
    • cp: ~48s
    • xcp: ~56s
  • Directory copy, warmed cache (3 runs each):
    • cp: ~6.9s
    • xcp: ~7.4s

NFS copy

xcp uses copy_file_range, which is filesystem aware. On NFSv4 this will result in the copy occurring server-side rather than transferring across the network. For large files this can be a significant win:

  • Single 4.1GB file on NFSv4 mount
    • cp: 378s
    • xcp: ~37s
Comments
  • Some tests are failing on Linux

    Some tests are failing on Linux

    ---- os::linux::tests::test_empty_extent stdout ----
    Error: Operation not supported (os error 95)
    thread 'os::linux::tests::test_empty_extent' panicked at 'assertion failed: `(left == right)`
      left: `1`,
     right: `0`: the test returned a termination value with a non-zero status code (1) which indicates a failure', <::std::macros::panic macros>:5:6
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    ---- os::linux::tests::test_extent_fetch_many stdout ----
    Error: Operation not supported (os error 95)
    thread 'os::linux::tests::test_extent_fetch_many' panicked at 'assertion failed: `(left == right)`
      left: `1`,
     right: `0`: the test returned a termination value with a non-zero status code (1) which indicates a failure', <::std::macros::panic macros>:5:6
    
    ---- os::linux::tests::test_extent_fetch stdout ----
    Error: Operation not supported (os error 95)
    thread 'os::linux::tests::test_extent_fetch' panicked at 'assertion failed: `(left == right)`
      left: `1`,
     right: `0`: the test returned a termination value with a non-zero status code (1) which indicates a failure', <::std::macros::panic macros>:5:6
    
    opened by cauebs 6
  • Progress bar is too large

    Progress bar is too large

    When copying, the progress bar is longer than the size of my terminal and it overflows to the next line. This is what I get when I copy a file.

    $ cargo run A.mp4 B.mp4
        Finished dev [unoptimized + debuginfo] target(s) in 0.11s
         Running `target/debug/xcp A.mp4 B.mp4`
    [00:00:00] [--------------------------------------------------------------------[00:00:00] 
    [#############>------------------------------------------------------[00:00:00] 
    [####################>-----------------------------------------------[00:00:00] 
    [###########################>----------------------------------------[00:00:00] 
    [########################################>---------------------------[00:00:00] 
    [###############################################>--------------------[00:00:00] 
    [######################################################>-------------[00:00:00] 
    [#############################################################>------[00:00:00] 
    [####################################################################[00:00:00] 
    [####################################################################[00:00:00] 
    [###############################################################################
    #] 751.60MB/751.60MB (0s)
    
    opened by ellishg 4
  • Support 32-bit platforms e.g. armv7l

    Support 32-bit platforms e.g. armv7l

    ~~This seems to be a fairly simple matter of switching over to libc functions that take off64_t instead of off_t, which on 32-bit platforms is i32 instead of i64.~~

    This seems to be a fairly simple matter of fallibly converting certain syscall parameters to off_t rather than casting them to i64. The conversion should only actually be fallible on 32-bit platforms, where off_t is i32 instead of i64.

    With these changes, cargo test succeeds on my Raspberry Pi 4 with Arch Linux ARM.

    (Kudos to the Rust compiler for barfing on the cast mismatches, else the program might have silently eaten large files instead of failing to compile.)

    opened by mmirate 3
  • Support for no-target-directory and hidden files

    Support for no-target-directory and hidden files

    A PR for some features that would be helpful to me. Feel free to close if these are not desired. I'm also happy to make changes.

    closes #5

    Commit Message:

    add option for no-target-director, analagous to cp's no-target-directory. Expected behavior is that when copying a directory to another directory, instead of creating a sub-folder in target, overwrite target.

    add option for hidden files. Default is to ignore hidden files.

    This is a little hacked in; it seems as though ignore's Walk could handle both .gitignore and hidden files on its own, but I may have missed something.

    opened by hwchen 3
  • Building fails on Termux

    Building fails on Termux

    Hello,

    I tried to build xcp 0.9.2 on Termux by cargo install, but it failed to compile.

    The command I typed:

    $ cargo install --locked xcp
    

    Versions:

    rustc 1.64.0
    cargo 1.64.0
    Termux Variables:
    TERMUX_API_VERSION=0.50.1
    TERMUX_APK_RELEASE=F_DROID
    TERMUX_APP_PACKAGE_MANAGER=apt
    TERMUX_APP_PID=9719
    TERMUX_IS_DEBUGGABLE_BUILD=0
    TERMUX_MAIN_PACKAGE_FORMAT=debian
    TERMUX_VERSION=0.118.0
    Packages CPU architecture:
    aarch64
    Subscribed repositories:
    # sources.list
    deb https://mirrors.pku.edu.cn/termux/termux-main/ stable main
    Updatable packages:
    All packages up to date
    termux-tools version:
    1.29.3
    Android version:
    12
    Kernel build information:
    Linux localhost 4.14.212-Velvet-Cyprus_v2.1 #1 SMP PREEMPT Tue Sep 13 07:06:30 UTC 2022 aarch64 Android
    Device manufacturer:
    Xiaomi
    Device model:
    Redmi Note 9S
    

    And the output:

    error[E0433]: failed to resolve: could not find `linux` in `os`
      --> /data/data/com.termux/files/home/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/xcp-0.9.2/src/os/linux.rs:22:14
       |                                                                                    22 | use std::os::linux::fs::MetadataExt;
       |              ^^^^^ could not find `linux` in `os`                                  
    error[E0599]: no method named `st_blocks` found for struct `std::fs::Metadata` in the current scope
       --> /data/data/com.termux/files/home/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/xcp-0.9.2/src/os/linux.rs:182:13
        |                                                                                   182 |     Ok(stat.st_blocks() < stat.st_size() / stat.st_blksize())
        |             ^^^^^^^^^ method not found in `std::fs::Metadata`                         |
        = help: items from traits can only be used if the trait is in scope                 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
        |                                                                                   17  | use std::os::android::fs::MetadataExt;
        |                                                                                   
    error[E0599]: no method named `st_size` found for struct `std::fs::Metadata` in the current scope
       --> /data/data/com.termux/files/home/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/xcp-0.9.2/src/os/linux.rs:182:32
        |                                                                                   182 |     Ok(stat.st_blocks() < stat.st_size() / stat.st_blksize())
        |                                ^^^^^^^ method not found in `std::fs::Metadata`        |
        = help: items from traits can only be used if the trait is in scope                 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
        |                                                                                   17  | use std::os::android::fs::MetadataExt;
        |                                                                                   
    error[E0599]: no method named `st_blksize` found for struct `std::fs::Metadata` in the current scope
       --> /data/data/com.termux/files/home/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/xcp-0.9.2/src/os/linux.rs:182:49
        |                                                                                   182 |     Ok(stat.st_blocks() < stat.st_size() / stat.st_blksize())
        |                                                 ^^^^^^^^^^ method not found in `std::fs::Metadata`
        |                                                                                       = help: items from traits can only be used if the trait is in scope
    help: the following trait is implemented but not in scope; perhaps add a `use` for it:      |
    17  | use std::os::android::fs::MetadataExt;                                                |
                                                                                            error[E0308]: mismatched types
        --> /data/data/com.termux/files/home/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/xcp-0.9.2/src/os/linux.rs:285:41
         |                                                                                  285  |             libc::ioctl(fd.as_raw_fd(), FS_IOC_FIEMAP, req_ptr)
         |             -----------                 ^^^^^^^^^^^^^ expected `i32`, found `u64`     |             |
         |             arguments to this function are incorrect                                  |
    note: function defined here                                                                 --> /data/data/com.termux/files/home/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.134/src/unix/linux_like/android/mod.rs:2824:12                         |
    2824 |     pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int;                      |            ^^^^^
    help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit       |
    285  |             libc::ioctl(fd.as_raw_fd(), FS_IOC_FIEMAP.try_into().unwrap(), req_ptr)
         |                                                      ++++++++++++++++++++                                                                                                Some errors have detailed explanations: E0308, E0433, E0599.                            For more information about an error, try `rustc --explain E0308`.
    error: could not compile `xcp` due to 5 previous errors
    
    opened by Potato1682 2
  • xcp fails to copy from btrfs to exfat

    xcp fails to copy from btrfs to exfat

    Copying a file from a btrfs source to an exfat destination fails with the error:

    Error: Operation not supported (os error 95)

    However, both cp and rsync have no issues copying the file. rsync with -P even displays the progress correctly.

    xcp: 0.9.1 rust: 1.63.0-1 kernel: 5.18.18 OS: Fedora 36 Arch: x86_64

    opened by dextersgenius 2
  • support for -no-target-directory

    support for -no-target-directory

    add option for no-target-directory, analagous to cp's no-target-directory. Expected behavior is that when copying a directory to another directory, instead of creating a sub-folder in target, overwrite target.

    opened by hwchen 2
  • Add NetBSD

    Add NetBSD

    I've packaged and merged xcp earlier today, http://mail-index.netbsd.org/pkgsrc-changes/2022/10/04/msg261531.html Please consider adding this to the README.md Thanks.

    opened by 0323pin 1
  • Explanation of thrashing mentioned in readme.

    Explanation of thrashing mentioned in readme.

    Readme mentions, it will thrash the spinning disk drive by reading metadata and copying at the same time. Isn't Receiving multiple read/write request at a time common for HDD on multi program and multi user system. Is there something happening which increases this significantly? How many parallel request will is send for one file, so that HDD thrashing becomes an issue? Is there a way to avoid it through configuration?

    opened by navneetankur 0
  • Copying file from virtual filesystems fails silently

    Copying file from virtual filesystems fails silently

    There is a known issue with copy_file_range() that will result in files copied from virtual filesystems (e.g. /proc, /sys) to copy the incorrect number of bytes (usually 0 in the case of /proc, but possibly other sizes). LWN has a good summary here:

    https://lwn.net/Articles/846403/

    Detecting such filesystems/files is hard, as there is no "FS is virtual" flag, so all file sizes are inherently suspect when working this way. This issue is exaserbated in the case of xcp's block-parallel driver (parblock), which needs to know the file size up-front to allocate work on the queues.

    This issue needs more investigation, and possibly some fundamental rearchitecting in the case of parallel block copy.

    bug enhancement 
    opened by tarka 0
  • Suboptimal experience of copying a large file to a slow USD thumb drive.

    Suboptimal experience of copying a large file to a slow USD thumb drive.

    If I start xcp normally, it shows as if the file were copied instantly, while in reality it is copied to cache (/proc/meminfo shows Dirty: as big as the file), with further actual copying happening outside xcp's control (i.e. progress bar).

    If I start xcp in a memory-limited cgroup, it copies the file gradually (dirty bytes does not exceed the limit I set for it, I see destination file size gradually increasing), but the progress bar is stuck at 0% until the file finishes growing to its normal size. After that it starts actually copying the file (with normal progress bar). The data is written to vfat USB drive twice: first zero bytes, then actual content.

    Shall xcp detect that it is copying the data to a USB drive and activate some O_DIRECT mode so that copy does not touch the cache and is easily abortable by user?

    opened by vi 0
  • Faulty detection of sparse files?

    Faulty detection of sparse files?

    The core of the detection of sparse files is:

    https://github.com/tarka/xcp/blob/ea28a4dbec5a9f43210fe72b5c6f827eba9bbaf6/src/os/linux.rs#L182

    I may be wrong, but I think the use of st_blksize here is a mistake.

    man 2 stat describes st_blksize as 'the "preferred" block size for efficient filesystem I/O.', and st_blocks as 'the number of blocks allocated to the file, in 512-byte units.' I checked with Rust code on a regular (non-sparse) file:

    [src/main.rs:7] meta.st_blksize() = 4096
    [src/main.rs:8] meta.st_blocks() = 1512
    [src/main.rs:9] meta.st_size() = 771765
    [src/main.rs:10] meta.st_size() / meta.st_blksize() = 188
    [src/main.rs:11] meta.st_size() / 512 = 1507
    

    I think these lines are the corresponding code in GNU cp. They use a constant ST_NBLOCKSIZE (from this header file) rather than anything from the stat struct.

    If so, the impact is probably minor - I think st_blksize is only likely to be bigger than 512, so it should never erroneously decide that a dense file is sparse. And it can still detect very sparse files (on my system, where holes are 7/8 of the total size), where it's likely to be most important to optimise copying. But it looks like it will miss other sparse files.

    opened by takluyver 0
  • failing syscalls on virtualbox share filesystem

    failing syscalls on virtualbox share filesystem

    Copying to a virtualbox filesystem leads to xcp printing an error and not copying the files.

    [pid 31325] statx(3, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_TYPE|STATX_MODE|STATX_NLINK|STATX_UID|STATX_GID|STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|STATX_BTIME|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0755, stx_size=20701696, ...}) = 0
    [pid 31325] openat(AT_FDCWD, "/media/sf_c/temp/test.out", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 4
    [pid 31325] ftruncate(4, 20701696)      = 0
    [pid 31325] flistxattr(3, NULL, 0)      = -1 EOPNOTSUPP (Operation not supported)
    

    after adding --no-perms

    [pid 31423] openat(AT_FDCWD, "/media/sf_c/temp/test.out", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 4
    [pid 31423] ftruncate(4, 20701696)      = 0
    [pid 31423] statx(3, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_TYPE|STATX_MODE|STATX_NLINK|STATX_UID|STATX_GID|STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|STATX_BTIME|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0755, stx_size=20701696, ...}) = 0
    [pid 31423] copy_file_range(3, NULL, 4, NULL, 20701696, 0) = -1 EINVAL (Invalid argument)
    

    kernel 5.10.11

    opened by the8472 2
  • [feature] remove copied files

    [feature] remove copied files

    Merry Christmas, first of all!

    How would you feel about a feature to remove copied files? Alternatively (or, even better, in addition) xcp could support running an external command after one or more files have been copied.

    opened by lnicola 1
Releases(v0.9.0)
  • v0.9.0(Oct 10, 2020)

    • Fix functional tests to correctly recognise failing tests; due to misunderstanding of test-case some functional-test failures were being interpreted as passing. See https://github.com/frondeus/test-case/issues/50 for details.
    • Correct order of permission copying to allow xattr to be set correctly.
    • Symlink handling was missing from the parblock driver.
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Sep 26, 2020)

    • Disable the parblock driver on Mac, as it's known to fail under stress testing.
    • Explicitly add FreeBSD, NetBSD and Dragonfly to OSs that work with the parblock driver after testing.
    • Disable xattr copy for some OSs that don't support it fully (NetBSD in particular).
    Source code(tar.gz)
    Source code(zip)
  • v0.7.3(Aug 2, 2020)

    • Fix for progress-bar wrapping on smaller terminals; thanks to @ellishg for the report and fix.
    • Additional internal optimisations and cleanups from @lnicola.
    Source code(tar.gz)
    Source code(zip)
  • v0.7.2(Apr 13, 2020)

  • v0.7.1(Dec 14, 2019)

  • v0.7.0(Dec 14, 2019)

    Features:

    • The flag --no-perms has been added to skip permission copying; thanks to @lnicola for this feature.
    • Extended file attributes (xattrs) are now copied on systems that support them.
    • The parblock driver now preserves file sparse blocks.

    Other improvments:

    • Some brute-force fuzz tests with randomly generated file-trees have been added, including random sparse files. These are slower so are not run with the default cargo test (unless you add the --ignored flag), but are run on CI.
    Source code(tar.gz)
    Source code(zip)
  • v0.6.2(Nov 23, 2019)

  • v0.6.1(Nov 23, 2019)

  • v0.6.0(Nov 18, 2019)

    The major changes in this version are:

    • The introduction of switchable 'drivers'. This has been added to facilitate experimenting with alternative strategies for copy optimisation. Currently 2 drivers are avalable:
      • 'parfile': the previous hard-coded xcp copy method, which parallelises tree-walking and per-file copying. This is the default.
      • 'parblock': An experimental driver that parallelises copying at the block level. This has the potential for performance improvements in some architectures, but increases complexity. It should be considered a work-in-progress; currently it does not support sparse files, does not play well with the progress bar, and will almost certainly eat your data. Testing is welcome.
    • A '--block-size' flag to configure size of copy operations.
    • The --no-target-directory (-T) flag from 'cp' is now supported (thanks to Walther Chen).
    Source code(tar.gz)
    Source code(zip)
Owner
Steve Smith
Most personal projects are on https://bitbucket.org/tarkasteve/
Steve Smith
🦀️atos for linux by rust - A partial replacement for Apple's atos tool for converting addresses within a binary file to symbols.

atosl-rs ??️ atos for linux by rust - A partial replacement for Apple's atos tool for converting addresses within a binary file to symbols. tested on

everettjf 60 Dec 29, 2022
Pink is a command-line tool inspired by the Unix man command.

Pink is a command-line tool inspired by the Unix man command. It displays custom-formatted text pages in the terminal using a subset of HTML-like tags.

null 3 Nov 2, 2023
Automatically verify your [Partial]Eq/Ord invariants

Reltester Relation tester is a small testing utility for automatically checking the correctness of PartialEq, PartialOrd, Eq, and Ord implementations.

Filippo Neysofu Costa 18 Mar 24, 2023
epNFTs, the first partial program-owned NFT Standard powered by Instruction Introspection and Transfer Hooks!

epNFT Standard: A Comprehensive Guide Introduction to epNFTs Welcome to the epNFT-standard repository, where we explore the first program-owned NFT st

epPlex 6 Mar 1, 2024
A general purpose Lisp🛸 intended for use as Sage's preprocessor language

sage-lisp This crate implements a standalone Lisp implementation, intended for use in the Sage preprocessor. (do (defun fact (n) (if (<=

adam mcdaniel 3 Apr 10, 2024
This tool was developed as part of a course on forensic analysis and cybersecurity. It is intended to be used as a training resource to help students understand the structure and content of job files in Windows environments.

Job File Parser Job File Parser is a Rust-based tool designed for parsing both legacy binary job files and modern XML job files used by the Windows Ta

Mehrnoush 3 Aug 12, 2024
Reviving the Research Edition Unix speak command

This repository contains the source code of Unix speak program that appeared in the Third (1973) to Sixth (1975) Research Unix editions, slightly adjusted to run on a modern computer. Details on the code's provenance and the methods employed for reviving it can be found in this blog post.

Diomidis Spinellis 31 Jul 27, 2022
fcp is a significantly faster alternative to the classic Unix cp(1) command

A significantly faster alternative to the classic Unix cp(1) command, copying large files and directories in a fraction of the time.

Kevin Svetlitski 532 Jan 3, 2023
zoxide is a blazing fast replacement for your cd command

zoxide A smarter cd command for your terminal zoxide is a blazing fast replacement for your cd command, inspired by z and z.lua. It keeps track of the

Ajeet D'Souza 8.7k Dec 31, 2022
Wordlet - a command line clone of Wordle, written in Rust.

Wordlet Wordlet is a command line clone of Wordle, written in Rust. Installation $ cargo install wordlet Usage After installation, start Wordlet by ty

Scott Luptowski 55 Oct 22, 2022
A clone of linux cal command, using rust programming language

CLI Calendar command What the project does This command was inspired by Linux Cal command that shows the current month calendar as output (by default)

Mohamed Djoudi Benarfa 2 Nov 16, 2022
A full featured, fast Command Line Argument Parser for Rust

clap Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcomma

null 10.4k Jan 10, 2023
A full featured, fast Command Line Argument Parser for Rust

clap Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcomma

Ed Page 0 Jun 16, 2022
A Rust curses library, supports Unix platforms and Windows

pancurses pancurses is a curses library for Rust that supports both Linux and Windows by abstracting away the backend that it uses (ncurses-rs and pdc

Ilkka Halila 360 Jan 7, 2023
Spawn multiple concurrent unix terminals in Discord

Using this bot can be exceedingly dangerous since you're basically granting people direct access to your shell.

Simon Larsson 11 Jun 1, 2021
A tool for automating terminal applications in Unix.

expectrl A tool for automating terminal applications in Unix. Using the library you can: Spawn process Control process Expect/Verify responces It was

Maxim Zhiburt 132 Dec 14, 2022
A small unix and windows lib to search for executables in PATH folders.

A small unix and windows lib to search for executables in path folders.

Robiot 2 Dec 25, 2021
Modern file system navigation tool on Unix

monat -- Modern file system Navigator 简体中文 Introduction monat is a Unix shell auxiliary command focusing on the navigation of the file system, especia

Pavinberg 8 May 10, 2022