-1

I am new to bash loops and trying to rename all files in a directory to their appropriate md5 values.

There are 5 sample files in the directory. For testing purpose, I am trying to first just print md5 hashes of all files in the directory using below command and it is working fine.

for i in `ls`; do md5sum $i; done 

Output:

edc47be8af3a7d4d55402ebae9f04f0a  file1
72cf1321d5f3d2e9e1be8abd971f42f5  file2
4b7b590d6d522f6da7e3a9d12d622a07  file3
357af1e7f8141581361ac5d39efa4d89  file4
1445c4c1fb27abd9061ada3b30a18b44  file5

Now I am trying to rename each file with its appropriate md5 hashes by following command:

for i in `ls`; do mv $i md5sum $i; done

Failed Output:

mv: target 'file1' is not a directory
mv: target 'file2' is not a directory
mv: target 'file3' is not a directory
mv: target 'file4' is not a directory
mv: target 'file5' is not a directory

What am I missing here?

Dharman
  • 30,962
  • 25
  • 85
  • 135
node_analyser
  • 1,502
  • 3
  • 17
  • 34

2 Answers2

-1

Syntax. Yes I was giving wrong syntax.

With some trial and errors with the command, I finally came up with the correct syntax.

I noticed that md5sum $i was giving me 2 column-ed output.

edc47be8af3a7d4d55402ebae9f04f0a  file1
72cf1321d5f3d2e9e1be8abd971f42f5  file2
4b7b590d6d522f6da7e3a9d12d622a07  file3
357af1e7f8141581361ac5d39efa4d89  file4
1445c4c1fb27abd9061ada3b30a18b44  file5

By firing second command for i in ls; do mv $i md5sum $i; done, I was basically telling terminal to do something like :

mv $i md5sum $i 

which, upto my knowledge, turns out to be

mv file1 <md5 value> file1  <-- this was the issue. 

How I resolved the issue?

I used cut command to filter out required value and made new one-liner as below:

for i in `ls`; do mv $i "$(md5sum $i | cut -d " " -f 1)"; done

[Edit] According to another answer and comment by @stark, @choroba and @tripleee, it is better to use * instead of ls.

for i in *; do mv $i "$(md5sum $i | cut -d " " -f 1)"; done

@choroba's answer is also a good addition here. Turning it into one-liner requirement, below is his solution:

for i in *; do m=$(md5sum $i); mv "$i" ${m%% *};done

node_analyser
  • 1,502
  • 3
  • 17
  • 34
  • 2
    Still [don't use `ls` in scripts.](https://mywiki.wooledge.org/ParsingLs) And [quote your variables.](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) – tripleee Jun 02 '21 at 10:03
-1

Your command is expanded to

mv file1 edc47be8af3a7d4d55402ebae9f04f0a file1

When mv has more than two non-option arguments, it understands the last argument to be the target directory to which all the preceding files should be moved. But there's no directory file1.

You can use parameter expansion to remove the filename from the string. Parameter expansion is usually faster then running an external command like cut or sed, but if you aren't renaming thousands of files, it probably doesn't matter.

for f in *; do
    m=$(md5sum "$f")
    mv "$f" ${m%% *}  # Remove everything after the first space
done

Also note that I don't parse the output of ls, but let the shell expand the glob. It's safer and works (with proper quoting) for filenames containing whitespace.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • You get it exactly right. I realised the mistake while doing some trial-and-errors. Secondly, I am looking for one-liner which can be directly fired from terminal. I tried your command `for i in *; do m=$(md5sum $i) mv "$i" ${m%% *};done` and somehow it's giving me error. – node_analyser Jun 02 '21 at 10:03
  • You miss a semicolon before `mv` – choroba Jun 02 '21 at 10:05
  • While doing some trials, I also came across approach similar to yours but gave me error. reference : https://unix.stackexchange.com/a/102651/232683 – node_analyser Jun 02 '21 at 10:06
  • I added semicolon and it's working perfectly fine. Awesome! I thought semi should only be used while whole command is complete in the `done` part. – node_analyser Jun 02 '21 at 10:08
  • 1
    No, you need to use newlines or semicolons to separate commands. – choroba Jun 02 '21 at 10:08
  • Got to learn a new thing today. Thank you. – node_analyser Jun 02 '21 at 10:10