Ubuntu – How to rename (unhide) all files and subdirectories within a directory

batch-renamecommand line

I want to make a script to "unhide" all files and directories inside a certain directory in one go, e.g. ./unhide test.

test/
├── sub1
│   └── .hiddenfile1
└── sub2
    └── .hiddendir
        ├── .hiddendirsub
        ├── .hiddenfile2
        └── not.hidden

Desired outcome:

test/
├── sub1
│   └── hiddenfile1
└── sub2
    └── hiddendir
        ├── hiddendirsub
        ├── hiddenfile2
        └── not.hidden

How can I do that?

I'm still new to this and I've been trying to find a solution using find, but stuck at -exec, and rename (or mv) because I'm still struggling to understand how this combination works. 🙁
So, I'll appreciate if anyone here can give a solution and detailed explanation as well. Thanks.

Best Answer

You can do that with find as follows:

find /path/to/test -depth -name ".*" -execdir rename -n 's|/\.|/|' {} +

This only prints the renaming actions, if it shows what you want remove the -n option.

Explanations

  • -depth – lets find process from bottom to top, renaming files before their parent directories
  • -name ".*" – lets find search for files (everything is a file) beginning with a dot – the dot is literal here, as this is not a regular expression
  • -execdir … + – execute in the matched file‘s directory
  • rename 's|/\.|/|' {} – replace the first occurence of “/.” from the matched file’s path (find’s placeholder for which is {}) with “/”, essentially removing the dot from the beginning of the filename
    This would be e.g. rename 's|/\.|/|' ./.hiddenfile1 in your case, this would be renamed to ./hiddenfile1.

Example run

$ tree -a
.
├── sub1
│   └── .hiddenfile1
└── sub2
    └── .hiddendir
        ├── .hiddendirsub
        ├── .hiddenfile2
        └── not.hidden

$ find ~/test -depth -name ".*" -execdir rename 's|/\.|/|' {} +
$ tree -a
.
├── sub1
│   └── hiddenfile1
└── sub2
    └── hiddendir
        ├── hiddendirsub
        ├── hiddenfile2
        └── not.hidden

Usage in a script

In a script you can simply use positional parameters instead of the path, it may be relative or absolute – just remember to quote correctly:

#!/bin/bash
find "$1" -depth -name ".*" -execdir rename -n 's|/\.|/|' {} +