Use vidir to quickly edit filenames in your editor

If you have installed moreutils (see below), you can type vidir to open up the current working directory in your $EDITOR. You can use all the power of your editor to edit and/or delete filenames and directories. Editing a line will rename the file or directory, deleting a line will remove the file or directory.

The following will list all your JPEG pictures in the current directory in your editor:

$ vidir *.jpeg

vidir is not recursive by default: if you want to recursively edit filenames, you can do:

$ find -type f -name '*.jpeg' | vidir -  # take note of the trailing dash -

Deleting non-empty directories

When trying to delete a non-empty directory, vidir will complain:

/usr/bin/vidir: failed to remove ./non-empty-directory: Directory not empty

We can use find again:

$ ls -1 non-empty-dir
file1.txt
file2.txt
$ find | vidir -
1   ./non-empty-dir
2   ./non-empty-dir/file1.txt
3   ./non-empty-dir/file2.txt

When we delete all the files from the directory and the directory itself, the directory will be deleted.

To see what vidir is actually doing, you can pass it the -v or --verbose flag:

$ find | vidir -v -
removed './non-empty-dir/file2.txt'
removed './non-empty-dir/file1.txt'
removed './non-empty-dir'

How to install

In Arch Linux, you can install the moreutils package with sudo pacman -S moreutils. On Debian distros, you can run sudo apt install moreutils.

Remove all files except a few in Bash

$ ls -1
153390909910_first
15339090991_second
15339090992_third
15339090993_fourth
15339090994_fifth
15339090995_sixth
15339090996_seventh
15339090997_eighth
15339090998_nineth
15339090999_tenth
15339091628_do_not_delete
root
root.sql

We want to delete all files that start with a timestamp (seconds since the epoch), except the newest file (15339091628_do_not_delete) and the files root and root.sql. The easiest way to do this, is enabling the shell option extglob (“extended globbing”), which allows us to use patterns to include or exclude files of operations:

$ shopt -s extglob
$ rm !(*do_not_delete|root*)

The last command will tell Bash to remove all files, except the ones that match either one of the patterns (everything ending with do_not_delete and everything starting with root). We delimite the patterns by using a pipe character |.

Other patterns that are supported by extglob include:

?(pattern-list)
      Matches zero or one occurrence of the given patterns

\*(pattern-list)
      Matches zero or more occurrences of the given patterns

+(pattern-list)
      Matches one or more occurrences of the given patterns

@(pattern-list)
      Matches one of the given patterns

!(pattern-list)
      Matches anything except one of the given patterns

To disable the extended globbing again:

$ shopt -u extglob

References

To read about all the options that extglob gives you, refer to man bash (search for Pathname Expansion). Searching for shopt in the same manual page will turn up all shell options. To see which shell options are currently enables for your shell, type shopt -p at the prompt.

Bash’ magic space

What does the “magic space” do?

Given the following:

$ find -wholename '*/path/to/file' -print -quit
$ man rm
$ rm -fv !-2:2

In the last line, feedback would be appreciated to see if we are indeed going to delete the second argument of two commands back. If you set Bash’ so-called “magic space”, history expansion will take place right away after typing a space after !-2:2:

$ rm -fv '*/path/to/file'

How to enable the magic space?

Put the following in your ~/.inputrc:

$if Bash
    Space: magic-space
$endif

Start a new session, or use bind -f ~/.inputrc to put the changes in effect immediately.

Other ways to achieve the same

You could also enable shopt -s histverify, which will perform the history expansion and give you another opportunity to modify the command before executing it. This requires you to press enter, though.