Jimson James
Jimson James

Reputation: 3327

find exec and strip extension from filenames

Any idea why this command is not working? btw, I'm trying to strip out the extensions of all csv files in current directory.

find -type f -iname "*.csv" -exec mv {} $(basename {} ".csv") \;

Tried many variants including the parameter expansions, xargs ... Even then all went futile.

Upvotes: 6

Views: 5011

Answers (2)

holzkohlengrill
holzkohlengrill

Reputation: 1242

This should do:

 find ./ -type f -iname "*.csv" -exec sh -c 'mv {} $(basename {} .csv)' \;

find is able to substitute {} with its findings since the quotes prevent executing the subshell until find is done. Then it executes the -exec part.


The problem why yours is not working is that $(basename {} ".csv") is executed in a subshell (-> $()) and evaluated beforehand. If we look at the command execution step-by-step you will see what happens:

  1. find -type f -iname "*.csv" -exec mv {} $(basename {} ".csv") \; - your command
  2. find -type f -iname "*.csv" -exec mv {} {} \; - subshell gets evaluated ($(basename {} ".csv") returns {} since it interprets {} as a literal)
  3. find -type f -iname "*.csv" -exec mv {} {} \; - as you see now: move does actually nothing

Upvotes: 10

hunteke
hunteke

Reputation: 3716

First, take care that you have no subdirectories; find, without extra arguments, will automatically recur into any directory below.

Simple approach: if you have a small enough number of files, just use the glob (*) operator, and take advantage of rename:

$ rename 's/.csv$//' *.csv

If you have too many files, use find, and perhaps xargs:

$ find . -maxdepth 1 -type f -name "*.csv" | xargs rename 's/.csv$//'

If you want to be really safe, tell find and xargs to delimit with null-bytes, so that you don't have weird filenames (e.g., with spaces or newlines) mess up the process:

$ find . -maxdepth 1 -type f -name "*.csv" -print0 | xargs -0 rename 's/.csv$//'

Upvotes: 2

Related Questions