0

I have a bunch of .txt files in a directory, and I want to be able to find these files and strip the extension from the file name.

I can find the files using:

$ find . -maxdepth 1 -type f -name "*.txt"
./0test.txt
./1test.txt
./2test.txt
./3test.txt
./4test.txt
./5test.txt
./6test.txt
./7test.txt
./8test.txt
./9test.txt

I then tried to use sed command to remove the ".txt" extension, like:

find . -maxdepth 1 -type f -name "*.txt" | sed "s/\.txt$//"

But I just get the file names listed without their extensions, and the actual file names remain unchanged.

So how do you actually change the file names themselves?

Broadsworde
  • 4,132
  • 4
  • 28
  • 45

3 Answers3

4

How about this in bash

for v in *.txt ; do mv "$v"  "$(basename "$v" .txt)"; done
steeldriver
  • 136,215
  • 21
  • 243
  • 336
SEWTGIYWTKHNTDS
  • 367
  • 1
  • 7
  • Thanks. That works pretty good. Nice and simple too! I just need to understand what it's actually doing. Do you have any ref/links to help me learn? I guess my goal of no loops and using sed isn't viable. – Broadsworde May 15 '21 at 13:49
  • man basename, its to strip directory and suffix from filenames, dirname is another useful command- man dirname :). $v is the v variable from the for loop. – SEWTGIYWTKHNTDS May 15 '21 at 14:38
  • You can get rid of double quotes and simply use for v in *.txt ; do mv $v $(basename $v .txt); done. To do the reverse use for v in * ; do mv $v $v.txt; done –  Oct 25 '21 at 10:35
2

$ in a regular expression matches the end of a string, you can't match characters after that, only before.

Also . needs to be escaped to stop it from having its special meaning (any character).

So:

find . -maxdepth 1 -type f -name "*.txt" | sed "s/\.txt$//"

If you're trying to rename the files, then you can use the same regular expression substitution with the perl-based rename command

rename "s/\.txt$//" *.txt

(you don't need find when all the files are in a single directory level), or a simple shell loop with mv:

for f in *.txt; do mv -n -- "$f" "${f%.txt}"; done
steeldriver
  • 136,215
  • 21
  • 243
  • 336
  • well I'm clearly having a dumb day, thanks for being gentle! So the output shows the files without extensions but the actual files remain untouched. Any thoughts? – Broadsworde May 15 '21 at 12:37
  • @Broadsworde what do you mean by "touched"? are you trying to modify the files' contents, or to rename them? If the latter, then sed is not the best tool for the job - you'd want rename (or mmv, or a shell loop using mv, or ...) – steeldriver May 15 '21 at 12:43
  • I'm trying to remove the extensions from the actual files. Is sed not capable of modifying file names, perhaps in conjunction with mv. Would prefer to not use rename and keep this a base install capable operation, and if it's possible to do without loops that would be ideal. Trying to keep it super simple. – Broadsworde May 15 '21 at 12:48
  • @Broadsworde you can use sed, but you'd need a loop (or something equivalent such as xargs) with mv . Rather than repeat myself here, please see this related answer Weird output while using sed to rename files – steeldriver May 15 '21 at 12:58
1

I know that this is an old question, maybe someone will benefit from this. Last night I needed to do this exact thing with sed, I asked God to show me, I had been trying this : echo filename.txt | sed 's/\.*$// and it just didn't work, it presented the filename including extension as is. This is what God revealed echo filename.txt | sed 's/\...*$//' filename

This removes not only 3 letter extensions but multiple extensions ie. tar.bz2, tar.xz and even tar.gz also.

echo filename.txt | sed 's/\...*$//'     filename
echo filename.epub | sed 's/\...*$//'     filename
echo filename.tar.xz | sed 's/\...*$//'     filename
echo filename.tar.bz2 | sed 's/\...*$//'     filename
echo filename.txt.gz| sed 's/\...*$//'     filename

This also has the desired result:

echo filename.txt | sed 's/\..*//'     filename
Ryan
  • 11