13

I hid some files using the command:

mv * .*

but now I am unable to find them. I tried using:

mv .* *

but nothing happened (an error was shown). If I run:

ls -la

it's showing:

total 8  
drwxrwxr-x 2 abhishek abhishek 4096 Mar  9 20:46 .  
drwxrwxr-x 4 abhishek abhishek 4096 Mar  9 20:46 ..  

Is there any way to recover my hidden files?

  • The key thing here is that the glob stars * are processed before mv ever gets the chance to look at the command line. You can use $ echo mv .* * to preview the command line before running it, so you can see what mv sees. – jpaugh Mar 11 '21 at 18:52

1 Answers1

44

Your files are not hidden, you have moved all files (and directories if any) one directory up.

This happens because mv * .* won't work as you think it will. The command mv will only move one file to one file (rename) or move one or multiple files to a directory. It won't move multiple files to multiple files with some smart renaming.


What happened?

Let's assume we have one directory and 3 files in our directory:

dir1
file1
file2
file3

Some Shells (e.g. bash, dash, ...) will expand your command to:

mv dir1 file1 file2 file3 . ..

Your expanded command fits the second form of the SYNOPSIS you find at man mv:

mv [OPTION]... SOURCE... DIRECTORY

Note the . and ..:

  • . is the current directory,
  • .. is one directory up.

The command means: move dir1, file1, file2 and file3 and . to ..; It will also essentially give an error, something like:

mv: cannot move '.' to '../.'

But given you have write permission in that directory, all other files have been moved. You can find your files in .. (= one directory up). However, files with same name have been overwritten and you won't know which files was in which directory before.


If you had a subdirectory .hidden-dir, it would have expanded to:

mv dir1 file1 file2 file3 . .. .hidden-dir

Then, all files would have been moved to .hidden-dir. However, this seems not the case for you, because the you would have seen .hidden-dir in your ls -la output.


How to fix

Run:

mv ../dir1 ../file1 ../file2 ../file3 .

However, you need to know the names.


What you should have used

mmv '*' '.#1'

or

rename 's/^/./' *
pLumo
  • 28,011
  • 2
  • 65
  • 97
  • 4
    and you won't know which files was in which directory before. - all the files that were moved will have the same ctime - ls -a -lcrt is useful to sort files by ctime with the most recent ones at the bottom. – Peter Cordes Mar 10 '21 at 15:25
  • 8
    It might have moved one directory up. It will move to whatever directory shows up last in the expansion of .*, which might some hidden directory, especially if this was done in a user's home directory or a directory under version control. I would recommend running ls -1d | tail -n1 in that directory. (in this case, he had an otherwise empty directory ... but others might not be so fortunate) – Joe Mar 10 '21 at 15:47
  • True, I added that information to the question. However, it is not the case here as OP issued ls -la without output. – pLumo Mar 10 '21 at 16:24
  • 2
    Shell also matters. For example, zsh doesn't match files .. nor . for any glob. – JoL Mar 10 '21 at 23:34
  • Thanks, also added that it only happens for some shells – pLumo Mar 11 '21 at 06:50
  • 1
    Note that mmv and rename may not be available everywhere. It would also probably be a good thing to emphasise the fact its mmvand notmv` for the hurried reader . – jcaron Mar 11 '21 at 13:11
  • for x in *; do mv -i "$x" ".$x"; done. – spectras Mar 12 '21 at 11:59
  • @spectras this will work if people have neither mmv or rename. However, at least rename is installed by default in Ubuntu and will be a lot faster for many files, as your loop will invoke mv for each file separately. – pLumo Mar 12 '21 at 15:20
  • We are talking microseconds on a command you would run a few times a month at most, I really doubt that is relevant… – spectras Mar 12 '21 at 20:20