xnx

Command-line utility for Linux, macOS and Windows performing sophisticated search and replace followed by calling external executables. It can be considered a kind of JSON shell.

Key features:

  • reads multiple substitution rules from a JSON5 file with the extension .xnx (using the json5 package);
  • implements loops and conditional processing (if-then-else);
  • allows staged (chained) rules in .xnx files;
  • allows importing (embedding) other .xnx files into a given one (either entire or filtered with an XPATH query);
  • supports an application configuration file with the extension .xnxconfig that allows redefining all keywords (keys with special meaning in .xnx files);
  • calls any external executables after all placeholders (keys) are replaced with the final values.
  • has Azure DevOps extension in a separate project;
  • produces multiple configuration files from a single source based on rules;
  • produces Flutter application icons as multiple .png files for all platforms from two .svg files (foreground and background);
  • produces light and dark multi-dimensional icons from a single .svg file: .icns for macOS, and .ico for Windows;
  • natively supports decompression via the archive package for .zip, .tar, [.tar].gz, [.tar].bz2, [.tar].Z;
  • performs search and replace with the multiple outputs in the MS Office files: .docx, .pptx, .xlsx (aka mail merge);
  • resolves environment variables in every rule;
  • allows passing arbitrary arguments to .xnx files;
  • resolves paths in every rule depending on OS it runs under;
  • implements in .xnx files commonly needed functions: trim, substr, regex match and replace, full path, file size, date/time math, and many more.

Supported encodings: UTF-8

Planning to add: UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE via the utf_ext package.

Usage:


xnx [OPTIONS]

-h, --help              - this help screen
-c, --app-config=FILE   - application configuration file in JSON5 format https://json5.org/;
                          defaults to default.xnxconfig in the directory where .xnx file is from
-x, --xnx=FILE          - the actual JSON5 file to process (the ruleset), see https://json5.org/;
                          default extension: .xnx
-d, --dir=DIR           - directory to start in; if -x, --xnx option is omitted, the application will
                          take the first .xnx file in this directory and use that as primary ruleset
-i, --import-dir=DIR    - default directory for .xnx files being imported into other .xnx files,
                          the application will export the environment variable _XNX_IMPORT_DIR
-m, --escape=MODE       - how to escape special characters before the expansion: quotes, xml, html (default: none),
                          the application will export the environment variable _XNX_ESCAPE
-q, --quiet             - quiet mode (no output, same as verbosity 0),
                          the application will export the environment variable _XNX_QUIET
-v, --verbose           - shows detailed log, the application will export the environment variable _XNX_VERBOSE,
-e, --each              - treat each plain argument independently (e.g. can pass multiple filenames as arguments)
                          see also -a, --xargs
-a, --xargs             - similar to -e, --each, but reads arguments from stdin
                          useful in a pipe with a file path finding command
-l, --list-only         - display all commands, but do not execute those; if no command specified, then show config,
                          the application will export the environment variable _XNX_LIST_ONLY
-s, --append-sep        - append record separator "," when filtering input config file (for "list-only" exclusively),
                          the application will export the environment variable _XNX_APPEND_SEP
-f, --force             - ignore timestamps and force conversion,
                          the application will export the environment variable _XNX_FORCE
-p, --compression=LEVEL - compression level for archiving-related operations (1..9) excepting BZip2,
                          the application will export the environment variable _XNX_COMPRESSION
-W, --wait-always       - always wait for a user to press <Enter> upon completion
-w, --wait-err          - wait for a user to press <Enter> upon unsuccessful completion

    --find              - just find recursively all files and sub-directories matching the glob pattern
                          in a given or the current directory and print those to stdout
    --print             - just print the arguments to stdout
    --env               - just print all environment variables to stdout
    --pwd               - just print the current working directory to stdout
    --copy              - just copy file(s) and/or directorie(s) passed as plain argument(s),
                          glob patterns are allowed
    --copy-newer        - just copy more recently updated file(s) and/or directorie(s) passed as plain argument(s),
                          glob patterns are allowed
    --move              - just move file(s) and/or directorie(s) passed as plain argument(s),
                          glob patterns are allowed
    --move-newer        - just move more recently updated file(s) and/or directorie(s) passed as plain argument(s),
                          glob patterns are allowed
    --rename            - just the same as --move
    --rename-newer      - just the same as --move-newer
    --mkdir             - just create directories passed as plain arguments
    --delete            - just delete file(s) and/or directorie(s) passed as plain argument(s),
                          glob patterns are allowed
    --remove            - just the same as --delete
    --bz2               - just compress a single source file to a single destination BZip2 file,
                          can be used with --move
    --unbz2             - just decompress a single BZip2 file to a single destination file,
                          can be used with --move
    --gz                - just compress a single source file to a single GZip file,
                          can be used with --move
    --ungz              - just decompress a single GZip file to a single destination file,
                          can be used with --move
    --tar               - just create a single destination archive file containing source files and/or
                          directories, can be used with --move
    --untar             - just untar a single archive file to a destination directory,
                          can be used with --move
    --tarbz2            - just a combination of --tar and --bz2,
                          can be used with --move
    --untarbz2          - just a combination of --untar and --unbz2,
                          can be used with --move
    --targz             - just a combination of --tar and --gz,
                          can be used with --move
    --untargz           - just a combination of --untar and --ungz,
                          can be used with --move
    --tarz              - just a combination of --tar and --Z,
                          can be used with --move
    --untarz            - just a combination of --untar and --unz,
                          can be used with --move
    --zip               - just zip source files and/or directories to a single destination
                          archive file, can be used with --move to delete the source
    --unzip             - just unzip single archive file to destination directory,
                          can be used with --move to delete the source
    --z                 - just compress a single source file to a single Z file,
                          can be used with --move to delete the source
    --unz               - just decompress a single Z file to a single destination file,
                          can be used with --move to delete the source
    --pack              - just compress source files and/or directories to a single destination
                          archive file depending on its extension, can be used with --move
    --unpack            - just decompress a single source archive file to destination files and/or
                          directories depending on the source extension, can be used with --move
        
Repo Examples App Bin