7

I like using the following command to print file names but it prints them with extensions.

find . -type f -printf '%f\n'

In my directory, there are many files with different extensions. I tried adding --ignore='*.*' both before and after -printf, but it didn't work. example; I have files myfile1.txt, myfile2.mp3, etc. I need it prints myfile1, myfile2, etc. How would I do this?

1
  • Since you specifically ask about find I’ll provide this aside in a comment. You can do this fluently with modern native bash: shopt -s globstar; files=(**/*); printf '%s\n' "${files[@]%.*}" — this could have odd behavior if a directory in the path has a . in it and the files in that path have no ., but I assume that combination is unlikely.
    – kojiro
    Jan 23, 2019 at 23:58

4 Answers 4

7

If I understand you correctly (I didn't, see second part of the answer), you want to avoid listing filenames that contain a dot character.

This will do that:

find . -type f ! -name '*.*'

The filename globbing pattern *.* would match any filename containing at least one dot. The preceding ! negates the sense of the match, which means that the pathnames that gets through to the end will be those of files that have no dots in their names. In really ancient shells, you may want to escape the ! as \! (or update your Unix installation). The lone ! won't invoke bash's history expansion facility.

To print only the filename component of the found pathname, with GNU find:

find . -type f ! -name '*.*' -printf '%f\n'

With standard find (or GNU find for that matter):

find . -type f ! -name '*.*' -exec basename {} \;

Before using this in a command substitution in a loop, see "Why is looping over find's output bad practice?".


To list all filenames, and at the same time remove everything after the last dot in the name ("remove the extension"), you may use

find . -type f -exec sh -c '
    for pathname do
        pathname=$( basename "$pathname" )
        printf "%s\n" "${pathname%.*}"
    done' sh {} +

This would send all found pathnames of all files to a short shell loop. The loop would take each pathname and call basename on it to extract the filename component of the pathname, and then print the resulting string with everything after the last dot removed.

The parameter expansion ${pathname%.*} means "remove the shortest string matching .* (a literal dot followed by arbitrary text) from the end of the value of $pathname". It would have the effect of removing a filename suffix after the last dot in the filename.

For more info about find ... -exec ... {} +, see e.g. "Understanding the -exec option of `find`".

5
  • Thanks for your help, I have tried all three, but they don't print anything. Am I missing something, on the same terminal, in the same directory find . -type f -printf '%f\n' works but as I asked in the question I need them without extensions.
    – kutlus
    Jan 23, 2019 at 19:53
  • @kutlus In that case, I (and the others) may have misunderstood your question. Do you want to remove everything after the last dot in the filename?
    – Kusalananda
    Jan 23, 2019 at 19:55
  • I just want the file name, example; some files are myfile1.txt, myfile2.mp3, i want it prints myfile1, myfile2. sorry if my questions wasn`t clear, thanks
    – kutlus
    Jan 23, 2019 at 19:58
  • @kutlus See updated answer.
    – Kusalananda
    Jan 23, 2019 at 20:02
  • Dear Kusalananda, thanks again for the very helpful answer. I have posted a new question closely related to this one, I wish you see it. unix.stackexchange.com/questions/496339/…
    – kutlus
    Jan 23, 2019 at 22:15
4

In Linux, there is no such thing as a file extension. A . in a file name has no significance whatsoever (notwithstanding that a . as the first character in a filename identifies it as a hidden file).

Also, checking the manual page for find on my system shows no --ignore option.

That said, if you want to ignore any files with a . in their name, you can use find's -not operator:

find -type f -not -name '*.*' -print
2
  • thanks but this doesn`t print anything.
    – kutlus
    Jan 23, 2019 at 19:49
  • If this does not print anything, then all files must have a . in their names.
    – DopeGhoti
    Jan 23, 2019 at 20:43
2

As other's have pointed out, "extensions" don't really mean anything to Unix systems. But we can remove them from a listing with a simple sed command.

e.g.

find * -type f -print | sed 's/\.[^.]*$//'

If there are directories and you don't want them to be shown in the listing then

find * -type f -printf "%f\n" | sed 's/\.[^.]*$//'

For a single directory we can just use ls instead of find

ls | sed 's/\.[^.]*$//'
1

try

find . -type f \! -name '*.*' -print

where

  • \! : not (! must be escaped)
  • name '*.*' : filename with extension
5
  • arg, not fast enough !!
    – Archemar
    Jan 23, 2019 at 19:27
  • Having to escape ! is why I usually suggest using -not.
    – DopeGhoti
    Jan 23, 2019 at 19:27
  • well it work w/o escape, I've been escaping it ever since SunOS 3.X... sight.
    – Archemar
    Jan 23, 2019 at 19:29
  • thanks but this doesn`t print anything.
    – kutlus
    Jan 23, 2019 at 19:48
  • In what shell do you need to escape it? It works without escaping in both zsh and bash. Both these shells only interpret a history expansion when the ! is accompanied by another character.
    – JoL
    Jan 23, 2019 at 23:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .