-1

I can remove file extensions if I know the extensions, for example to remove .txt from files:

foreach file (`find . -type f`)
    mv $file `basename $file .txt`
end

However if I don't know what kind of file extension to begin with, how would I do this?

I tried:

foreach file (`find . -type f`)
mv $file `basename $file .*`
end

but it wouldn't work.

Ian Chang
  • 27
  • 1
  • 4
  • Are there additional "."s in the file names? If not, I would try ```foreach file (find . -type f) set newfile = `basename file | awk 'BEGIN{FS="."}{print $1}'` mv $file $newfile end``` – eclark Jan 12 '17 at 00:31
  • Which shell are you using? Csh? You might get better responses if you tagged it with the correct tag ([tag:csh]), assuming I've identified it correctly. I've edited the tag for you — fix if I'm wrong. – Jonathan Leffler Jan 12 '17 at 01:20
  • @IanChang: Do you *have* to do it in csh? Csh is [not very convenient](https://www-uxsup.csx.cam.ac.uk/misc/csh.html) for programming. – user1934428 Jan 12 '17 at 07:41
  • @IanChang: Please consider for next time: if you want an answer that works on a specific `shell`, please specify the `shell` when you post the question. Originally, you only posted this question with the `shell` tag and I and other folks spent our time writing `bash` answers that will not work on the `csh` shell, which you specified later. – Jamil Said Jan 12 '17 at 19:26

4 Answers4

3

What shell is this? At least in bash you can do:

find . -type f | while read -r; do
    mv -- "$REPLY" "${REPLY%.*}"
done

(The usual caveats apply: This doesn't handle files whose name contains newlines.)

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • @Carpetsmoker True, but I never claimed it did, and when I wrote this answer, the question didn't mention any particular shell. – melpomene Jan 12 '17 at 18:22
  • Alright, fair enough :-) Didn't check the entire question history, but in general csh questions have a habit of accumulating bash answers ;-) – Martin Tournoij Jan 12 '17 at 18:32
2

You can use sed to compute base file name.

foreach file (`find . -type f`)
    mv $file `echo $file | sed -e 's/^\(.*\)\.[^.]\+$/\1/'`
end
2

Be cautious: The command you seek to run could cause loss of data!

If you don't think your file names contain newlines or double quotes, then you could use:

find . -type f -name '?*.*' |
sed 's/\(.*\)\.[^.]*$/mv "&" "\1"/' |
sh

This generates your list of files (making sure that the names contain at least one character plus a .), runs each file name through the sed script to convert it into an mv command by effectively removing the material from the last . onwards, and then running the stream of commands through a shell.

Clearly, you test this first by omitting the | sh part. Consider running it with | sh -x to get a trace of what the shell's doing. Consider making sure you capture the output of the shell, standard output and standard error, into a log file so you've got a record of the damage that occurred.

Do make sure you've got a backup of the original set of files before you start playing with this. It need only be a tar file stored in a different part of the directory hierarchy, and you can remove it as soon as you're happy with the results.

You can choose any shell; this doesn't rely on any shell constructs except pipes and single quotes and double quotes (pretty much common to all shells), and the sed script is version neutral too.

Note that if you have files xyz.c and xyz.h before you run this, you'll only have a file xyz afterwards (and what it contains depends on the order in which the files are processed, which needn't be alphabetic order).

If you think your file names might contain double quotes (but not single quotes), you can play with the changing the quotes in the sed script. If you might have to deal with both, you need a more complex sed script. If you need to deal with newlines in file names, then it is time to (a) tell your user(s) to stop being silly and (b) fix the names so they don't contain newlines. Then you can use the script above. If that isn't feasible, you have to work a lot harder to get the job done accurately — you probably need to make sure you've got a find that supports -print0, a sed that supports -z and an xargs that supports -0 (installing the most recent GNU versions if you don't already have the right support in place).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

It's very simple:

$ set filename=/home/foo/bar.dat
$ echo ${filename:r}
/home/foo/bar

See more in man tcsh, in "History substitution":

r

Remove a filename extension '.xxx', leaving the root name.

uzsolt
  • 5,832
  • 2
  • 20
  • 32