npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fileutils-cli

v1.0.1

Published

A collection of powerful command line file utilities

Downloads

28

Readme

FileUtils-CLI

A cross-platform collection of command line tools for file interactions

This project is the continuation of Rename-CLI to provide powerful, file-interaction tools with a unified syntax across platforms.

Features

  • Variable replacement and filtering (powered by Nunjucks)
  • Glob file matching
  • Command history with ability to undo entire commands or individual operations and re-run commands
  • Ability to save commands as favorites to re-run them quickly
  • Customize by adding your own variables and filters
  • Auto-indexing when moving/copying multiple files to the same file name

Usage

fileutils [command] [command options]

| Command | Alias(es) | Description | | ----- | ----- | ----- | | alias | a | alias a sub-command as a global command | | copy | c, cp, cpy | copy one or more files/directories to a destination (with variable support) | | download | d, dl, get | download a file from the internet (with variable support) | | extract | e, unzip, gunzip, tar | extract zip, tar, gzip, and bzip archives | | favorites | f, favourites | run, view, and edit favorited commands | | hash | md5, sha1, sha256, sha512 | get the hash of one or more files (use the appropriate alias for the algorithm you need) | | help | | view help (works with individual commands as well) | | history | h | view, undo, re-run, copy, and favorite past commands | | link | l, ln, mklink | create soft or hard links to one or more files (with variable support) | | move | m, mv, r, rename | move/rename one or more files/directories (with variable support) | | open | o, launch, start | open files in their default application or an application of your choice | | undo | u | undo the last undoable command that hasn't already been undone |

To save yourself some keystrokes, the fileutils command can also be run via the fu alias. Additionally, shortcuts to any of the sub-commands can be created via the alias command. These allow you to bypass the need to type fu or fileutils to run aliased commands.


Installation

The preferred methods of installation are via NPM or Homebrew.

NPM

First install NodeJS via package manager, NVM, or other preferred method. Then run the following in an elevated command/PowerShell window or with sudo (if necessary):

npm i -g fileutils-cli

Homebrew:

Coming Soon

If you don't want to install Node, the untested binary versions can be downloaded from the Releases page or via Chocolatey.

Chocolatey:

Coming Soon

Alias

Alias a sub-command as a global command. Since existing commands vary by OS, you can create global aliases for individual sub-commands on your own. For instance, on Windows there is no mv command so you can simply run fileutils alias move mv and move/rename files via mv like you would on Unix. This only works if installed via NPM or Homebrew.

Usage

fileutils alias <subcommand> <command>

Where subcommand is the command in FileUtils (move, copy, download, etc), and command is the alias you would like to create.

Note: on Windows, you will need to remove aliases manually if you uninstall FileUtils.


Copy

Copy one or more files/directories with variable support.

Usage

fileutils copy [options] [input-files..] [destination]

Or specify no options to launch an interactive terminal interface with live previews of the output(s) of your command.

To save you keystrokes, if the destination name/pattern does not contain a file extension the original file extension will be preserved. Also, you can specify the --create-dirs option to automatically create any missing directories.

Options

-f, --force: Forcefully overwrite existing files and create missing directories
-s, --sim, --dry-run: Simulate and print operations without actually moving any files
-n, --no-index: Do not automatically append an index when multiple operations result in the same destination path
-k, --keep: Append a number to destination file name if the file already exists
-d, --ignore-dirs: Do not move/rename directories
--sort: Sort files before running operations. Choices: none (default), alphabet, reverse-alphabet, date-create, reverse-date-create, date-modified, reverse-date-modified, size, reverse-size
-v, --verbose: Verbose logging
--no-trim: Do not trim whitespace at beginning or end of destination file names
--no-ext: Do not automatically append the original file extension if an extension isn't supplied
--create-dirs: Automatically create missing directories
--no-undo: Don't write to command history

Built-in Variables

{{i}} - Override where the file index will go if there are multiple files being named the same name. By default, it is appended to the end of the file name.
{{f}} - The original name of the file. Alias: fileName
{{ext}} - The original file extension of the file
{{isDirectory}} - true if the current input is a directory, false otherwise
{{p}} - The name of the parent directory. Alias: parent
{{date.current}} - The current date/time. Alias: date.now
{{date.create}} - The date/time the file was created
{{date.modify}} - The date/time the file was last modified
{{date.access}} - The date/time the file was last accessed
{{os.homedir}} - The path to the current user's home directory
{{os.platform}} - The operating system platform: darwin, linux, or windows
{{os.user}} - The username of the current user
{{guid}} - A pseudo-random GUID
{{stats}} - All the input file's stats https://nodejs.org/api/fs.html#fs_class_fs_stats
{{parsedPath}} - The input file's parsed path https://nodejs.org/api/path.html#path_path_parse_path
{{exif.iso}} - The ISO sensitivity of the camera when the photo was taken
{{exif.fnum}} - The F-stop number of the camera when the photo was taken
{{exif.exposure}} - The exposure time of the camera when the photo was taken. Use the fraction filter to convert decimals to fractions
{{exif.date}} - The date on the camera when the photo was taken
{{exif.width}} - The pixel width of the photo
{{exif.height}} - The pixel height of the photo
{{id3.title}} - The title of the song
{{id3.artist}} - The artist of the song
{{id3.album}} - The album of the song
{{id3.year}} - The year of the song
{{id3.track}} - The track number of the song
{{id3.totalTracks}} - The number of tracks on the album

See Filters and Examples for some examples of how to use filters and variables.


Download

Download a file from the internet.

Usage

fileutils download <url> [output path]

If no output path is specified, the file will be downloaded to the current directory and the file name guessed from the URL.

Options

-t, --tries - Number of retries (defaults to 20). To disable retries, set to 0
--max-redirect, --max-redirects - The maximum number of redirections to follow for a resource (defaults to 20)
-q, --quiet - Turn off logging and progress bar
-v, --verbose - Verbose logging

Variables

{{f}} - The original name of the file. Alias: fileName
{{ext}} - The original file extension of the file
{{date.current}} - The current date/time. Alias: date.now
{{os.homedir}} - The path to the current user's home directory
{{os.platform}} - The operating system platform: darwin, linux, or windows
{{os.user}} - The username of the current user
{{guid}} - A pseudo-random GUID


Extract

Extract zip, tar, gzip, and bzip archives.

Usage

fileutils extract <archive file> [output directory]

The output directory is optional. If you don't specify an output directory, the archive will extract into a directory of the same name.

Options

-s, --strip - Remove the specified number of leading directories from the extracted files
-f, --filter - Filter out the specified file extensions from the output (separated by space)
-v, --verbose - Verbose logging


Favorites

Run, view, and edit favorited commands.

fileutils favorites [id or alias]

When you specify an ID or alias of a favorite, that command is instantly run. If you don't specify anything, then you will be taken to a terminal UI with your list of favorites to edit, delete, or re-run them.


Hash

Get the hash(es) of one or more files.

Usage

fileutils hash <files..>

If you use the hash command, it defaults to an MD5 hash. If you need a different algorithm, use one of the aliases: sha1, sha256, sha512.

Options

-c, --copy - Copy the hash to the clipboard


History

View, undo, re-run, copy, and favorite past commands

Usage

fileutils history


Link

Create soft or hard links to one or more files.

Usage

fileutils link [options] [input-files..] [destination]

Or specify no options to launch an interactive terminal interface with live previews of the output(s) of your command.

To save you keystrokes, if the destination name/pattern does not contain a file extension the original file extension will be preserved. Also, you can specify the --create-dirs option to automatically create any missing directories.

Options

-f, --force: Forcefully overwrite existing files and create missing directories
-s, --soft: Create a soft link instead of a hard link -S, --sim, --dry-run: Simulate and print operations without actually moving any files
-n, --no-index: Do not automatically append an index when multiple operations result in the same destination path
-k, --keep: Append a number to destination file name if the file already exists
-d, --ignore-dirs: Do not move/rename directories
--sort: Sort files before running operations. Choices: none (default), alphabet, reverse-alphabet, date-create, reverse-date-create, date-modified, reverse-date-modified, size, reverse-size
-v, --verbose: Verbose logging
--no-trim: Do not trim whitespace at beginning or end of destination file names
--no-ext: Do not automatically append the original file extension if an extension isn't supplied
--create-dirs: Automatically create missing directories
--no-undo: Don't write to command history

Built-in Variables

{{i}} - Override where the file index will go if there are multiple files being named the same name. By default, it is appended to the end of the file name.
{{f}} - The original name of the file. Alias: fileName
{{ext}} - The original file extension of the file
{{isDirectory}} - true if the current input is a directory, false otherwise
{{p}} - The name of the parent directory. Alias: parent
{{date.current}} - The current date/time. Alias: date.now
{{date.create}} - The date/time the file was created
{{date.modify}} - The date/time the file was last modified
{{date.access}} - The date/time the file was last accessed
{{os.homedir}} - The path to the current user's home directory
{{os.platform}} - The operating system platform: darwin, linux, or windows
{{os.user}} - The username of the current user
{{guid}} - A pseudo-random GUID
{{stats}} - All the input file's stats https://nodejs.org/api/fs.html#fs_class_fs_stats
{{parsedPath}} - The input file's parsed path https://nodejs.org/api/path.html#path_path_parse_path
{{exif.iso}} - The ISO sensitivity of the camera when the photo was taken
{{exif.fnum}} - The F-stop number of the camera when the photo was taken
{{exif.exposure}} - The exposure time of the camera when the photo was taken. Use the fraction filter to convert decimals to fractions
{{exif.date}} - The date on the camera when the photo was taken
{{exif.width}} - The pixel width of the photo
{{exif.height}} - The pixel height of the photo
{{id3.title}} - The title of the song
{{id3.artist}} - The artist of the song
{{id3.album}} - The album of the song
{{id3.year}} - The year of the song
{{id3.track}} - The track number of the song
{{id3.totalTracks}} - The number of tracks on the album

See Filters and Examples for some examples of how to use filters and variables.


Move

Move/rename one or more files/directories with variable support.

Usage

fileutils move [options] [input-files..] [destination]

Or specify no options to launch an interactive terminal interface with live previews of the output(s) of your command.

To save you keystrokes, if the destination name/pattern does not contain a file extension the original file extension will be preserved. Also, you can specify the --create-dirs option to automatically create any missing directories.

Options

-f, --force: Forcefully overwrite existing files and create missing directories
-s, --sim, --dry-run: Simulate and print operations without actually moving any files
-n, --no-index: Do not automatically append an index when multiple operations result in the same destination path
-k, --keep: Append a number to destination file name if the file already exists
-d, --ignore-dirs: Do not move/rename directories
--sort: Sort files before running operations. Choices: none (default), alphabet, reverse-alphabet, date-create, reverse-date-create, date-modified, reverse-date-modified, size, reverse-size
-v, --verbose: Verbose logging
--no-trim: Do not trim whitespace at beginning or end of destination file names
--no-ext: Do not automatically append the original file extension if an extension isn't supplied
--create-dirs: Automatically create missing directories
--no-undo: Don't write to command history
--no-move: Do not move files if their new file path points to a different directory

Built-in Variables

{{i}} - Override where the file index will go if there are multiple files being named the same name. By default, it is appended to the end of the file name.
{{f}} - The original name of the file. Alias: fileName
{{ext}} - The original file extension of the file
{{isDirectory}} - true if the current input is a directory, false otherwise
{{p}} - The name of the parent directory. Alias: parent
{{date.current}} - The current date/time. Alias: date.now
{{date.create}} - The date/time the file was created
{{date.modify}} - The date/time the file was last modified
{{date.access}} - The date/time the file was last accessed
{{os.homedir}} - The path to the current user's home directory
{{os.platform}} - The operating system platform: darwin, linux, or windows
{{os.user}} - The username of the current user
{{guid}} - A pseudo-random GUID
{{stats}} - All the input file's stats https://nodejs.org/api/fs.html#fs_class_fs_stats
{{parsedPath}} - The input file's parsed path https://nodejs.org/api/path.html#path_path_parse_path
{{exif.iso}} - The ISO sensitivity of the camera when the photo was taken
{{exif.fnum}} - The F-stop number of the camera when the photo was taken
{{exif.exposure}} - The exposure time of the camera when the photo was taken. Use the fraction filter to convert decimals to fractions
{{exif.date}} - The date on the camera when the photo was taken
{{exif.width}} - The pixel width of the photo
{{exif.height}} - The pixel height of the photo
{{id3.title}} - The title of the song
{{id3.artist}} - The artist of the song
{{id3.album}} - The album of the song
{{id3.year}} - The year of the song
{{id3.track}} - The track number of the song
{{id3.totalTracks}} - The number of tracks on the album

See Filters and Examples for some examples of how to use filters and variables.


Open

Open files in their default application or an application of your choice

Usage

fileutils open <files..>

Options

-a, --app - Open in the specified app instead of the default application


Undo

Undo the last undoable command that hasn't already been undone.

Usage

fileutils undo

If you're unsure what the last command was that is undoable and hasn't already been undone, you're better off using history to view the commands and undo from there.


Filters and Examples

You can modify variable values by applying filters. Multiple filters can be chained together. Nunjucks, the underlying variable-replacement engine, has many filters available and FileUtils has a few of its own. Expand for more info.

String case manipulation

  • {{f|lower}} - Something Like This.txt → something like this.txt
  • {{f|upper}} - Something Like This.txt → SOMETHING LIKE THIS.txt
  • {{f|camel}} - Something Like This.txt → somethingLikeThis.txt
  • {{f|pascal}} - Something Like This.txt → SomethingLikeThis.txt
  • {{f|kebab}} - Something Like This.txt → something-like-this.txt
  • {{f|snake}} - Something Like This.txt → something_like_this.txt

replace('something', 'replacement') - replace a character or string with something else.

rename "bills file.pdf" "{{ f | replace('bill', 'mary') | pascal }}"

bills file.pdf → MarysFile.pdf

date - format a date to a specific format, the default is yyyyMMdd if no parameter is passed. To use your own format, simply pass the format as a string parameter to the date filter. Formatting options can be found here.

rename *.txt "{{ date.current | date }}-{{f}}"

a.txt → 20200502-a.txt
b.txt → 20200502-b.txt
c.txt → 20200502-c.txt

rename *.txt "{{ date.current | date('MM-dd-yyyy') }}-{{f}}"

a.txt → 05-02-2020-a.txt
b.txt → 05-02-2020-b.txt
c.txt → 05-02-2020-c.txt

match(RegExp[, flags, group num/name]) - match substring(s) using a regular expression. The only required parameter is the regular expression (as a string), it also allows for an optional parameter flags (a string containing any or all of the flags: g, i, m, s, u, and y, more info here), and an optional parameter of the group number or name. Named groups cannot be used with the global flag.

rename *ExpenseReport* "archive/{{ f | match('^.+(?=Expense)') }}/ExpenseReport.docx" --createdirs

JanuaryExpenseReport.docx → archive/January/ExpenseReport.docx
MarchExpenseReport.docx → archive/March/ExpenseReport.docx

regexReplace(RegExp[, flags, replacement]) - replace the first regex match with the replacement string. To replace all regex matches, pass the g flag. flags and replacement are optional, the default value for replacement is an empty string.

rename test/* "{{ f | regexReplace('(^|e)e', 'g', 'E') }}"

test/eight.txt → Eight.txt
test/eighteen.txt → EightEn.txt
test/eleven.txt → Eleven.txt

padNumber(length) - put leading zeroes in front of a number until it is length digits long. If length is a string, it will use the string's length.

rename --create-dirs "Absent Sounds/*" "{{id3.year}}/{{id3.artist}}/{{id3.album}}/{{ id3.track | padNumber(id3.totalTracks) }} - {{id3.title}}{{ext}}"

Absent Sounds/Am I Alive.mp3 → 2014/From Indian Lakes/Absent Sounds/05 - Am I Alive.mp3
Absent Sounds/Awful Things.mp3 → 2014/From Indian Lakes/Absent Sounds/07 - Awful Things.mp3
Absent Sounds/Breathe, Desperately.mp3 → 2014/From Indian Lakes/Absent Sounds/03 - Breathe, Desperately.mp3
Absent Sounds/Come In This Light.mp3 → 2014/From Indian Lakes/Absent Sounds/01 - Come In This Light.mp3
Absent Sounds/Fog.mp3 → 2014/From Indian Lakes/Absent Sounds/10 - Fog.mp3
Absent Sounds/Ghost.mp3 → 2014/From Indian Lakes/Absent Sounds/06 - Ghost.mp3
Absent Sounds/Label This Love.mp3 → 2014/From Indian Lakes/Absent Sounds/02 - Label This Love.mp3
Absent Sounds/Runner.mp3 → 2014/From Indian Lakes/Absent Sounds/08 - Runner.mp3
Absent Sounds/Search For More.mp3 → 2014/From Indian Lakes/Absent Sounds/09 - Search For More.mp3
Absent Sounds/Sleeping Limbs.mp3 → 2014/From Indian Lakes/Absent Sounds/04 - Sleeping Limbs.mp3

Customize

You can expand upon and overwrite much of the default functionality by creating your own variables and filters. Expand for more info.

Variables

The first time you run the rename command a file will be created at ~/.fu/userData.js, this file can be edited to add new variables that you can access with {{variableName}} in your new file name. You can also override the built-in variables by naming your variable the same. The userData.js file contains some examples.

// These are some helpful libraries already included in rename-cli
// All the built-in nodejs libraries are also available
// const exif = require('jpeg-exif'); // https://github.com/zhso/jpeg-exif
// const fs = require('fs-extra'); // https://github.com/jprichardson/node-fs-extra
// const Fraction = require('fraction.js'); // https://github.com/infusion/Fraction.js
// const date-fns = require('date-fns'); // https://date-fns.org/

module.exports = function(fileObj, descriptions) {
  let returnData = {};
  let returnDescriptions = {};

  // Put your code here to add properties to returnData
  // this data will then be available in your output file name
  // for example: returnData.myName = 'Your Name Here';
  // or: returnData.backupDir = 'D:/backup';

  // Optionally, you can describe a variable and have it show when printing help information
  // add the same path as a variable to the returnDescriptions object with a string description
  // for example: returnDescriptions.myName = 'My full name';
  // or: returnDescriptions.backupDir = 'The path to my backup directory';

  if (!descriptions) return returnData;
  else return returnDescriptions;
};

The fileObj that is passed to the function will look something like this:

{
  i: '--FILEINDEXHERE--',
  f: 'filename',
  fileName: 'filename',
  ext: '.txt',
  isDirectory: false,
  p: 'parent-directory-name',
  parent: 'parent-directory-name',
  date: {
    current: 2020-11-25T17:41:58.303Z,
    now: 2020-11-25T17:41:58.303Z,
    create: 2020-11-24T23:38:25.455Z,
    modify: 2020-11-24T23:38:25.455Z,
    access: 2020-11-24T23:38:25.516Z
  },
  os: {
    homedir: '/Users/my-user-name',
    platform: 'darwin',
    hostname: 'ComputerName.local',
    user: 'my-user-name'
  },
  guid: 'fb274642-0a6f-4fe6-8b07-0bac4db5c87b',
  customGuid: [Function: customGuid],
  stats: Stats {
    dev: 16777225,
    mode: 33188,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    blksize: 4096,
    ino: 48502576,
    size: 1455,
    blocks: 8,
    atimeMs: 1606261105516.3499,
    mtimeMs: 1606261105455.4163,
    ctimeMs: 1606261105486.9072,
    birthtimeMs: 1606261105455.093,
    atime: 2020-11-24T23:38:25.516Z,
    mtime: 2020-11-24T23:38:25.455Z,
    ctime: 2020-11-24T23:38:25.487Z,
    birthtime: 2020-11-24T23:38:25.455Z
  },
  parsedPath: {
    root: '/',
    dir: '/Users/my-user-name/Projects/node-rename-cli',
    base: 'filename.txt',
    ext: '.txt',
    name: 'filename'
  },
  exif: { iso: '', fnum: '', exposure: '', date: '', width: '', height: '' },
  id3: {
    title: '',
    artist: '',
    album: '',
    year: '',
    track: '',
    totalTracks: ''
  }
}

Filters

The first time you run the rename command a file will be created at ~/.fu/userFilters.js, this file can be edited to add new filters that you can access with {{someVariable | myNewFilter}} in your new file name.

One place custom filters can be really handy is if you have files that you often receive in some weird format and you then convert them to your own desired format. Instead of writing some long, complex new file name, just write your own filter and make the new file name {{f|myCustomFilterName}}. You can harness the power of code to do really complex things without having to write a complex command.

Each filter should accept a parameter that contains the value of the variable passed to the filter (str in the example below). You can optionally include more of your own parameters as well. The function should also return a string that will then be inserted into the new file name (or passed to another filter if they are chained). The userFilters.js file contains some examples.

// Uncomment the next line to create an alias for any of the default Nunjucks filters https://mozilla.github.io/nunjucks/templating.html#builtin-filters
// const defaultFilters = require('../nunjucks/src/filters');
// These are some helpful libraries already included in rename-cli
// All the built-in nodejs libraries are also available
// const exif = require('jpeg-exif'); // https://github.com/zhso/jpeg-exif
// const fs = require('fs-extra'); // https://github.com/jprichardson/node-fs-extra
// const Fraction = require('fraction.js'); // https://github.com/infusion/Fraction.js
// const { format } = require('date-fns'); // https://date-fns.org/

module.exports = {
  // Create an alias for a built-in filter
  // big: defaultFilters.upper,
  // Create your own filter
  // match: function(str, regexp, flags) {
  //   if (regexp instanceof RegExp === false) {
  //     regexp = new RegExp(regexp, flags);
  //   }
  //   return str.match(regexp);
  // }
};