8

We can copy some file by extensions like this:

cp *.txt ../new/ 

but how can I copy all files that have no extension?

3
  • What other things do the files have in common besides having no extension? Commented Jul 3, 2015 at 1:58
  • Nothing. for example files are like this : a, a.txt, b, b.txt ... Commented Jul 3, 2015 at 2:00
  • Use find command and remove anything with (extension) dot. For example find . -type f | grep -v "\." Commented Sep 10, 2024 at 7:19

3 Answers 3

16

The answer from @ubaid-ashraf is almost there. The way to specify file with no extension, in ksh would be:

cp -- !(*.*) /new/path/ 

so that any file with dot in file name is skipped.

For that to work in bash, you need to enable the extglob option (shopt -s extglob) and the kshglob option in zsh (set -o kshglob).

6
  • the problem with this (and @ubaid-ashraf 's solution) is that it will also move directories , since most directories will not have any extensions. My solution would ensure that there are no directories moved Commented Jul 3, 2015 at 4:49
  • 2
    No it would not move directories. cp would skip directories unless used with -r or -R option. Commented Jul 3, 2015 at 4:56
  • And what if I have a file called my.file.txt? Commented Jul 3, 2015 at 7:36
  • 1
    why do you use -- after cp? i do that without -- and it works. btw, what is usage of --? Commented Oct 31, 2015 at 16:37
  • 2
    @hoosssein Double dash prevents anything that follows to be treated as command line options. If there are odd file names like "-r" or "-s", double dash can help guarding against potential disaster. Commented Nov 2, 2015 at 5:08
6

You can do something like:

cp -- !(*.txt) /path/to/directory 

The above code will copy all the files without .txt extension. You can also give multiple extension via pipe character.

For example:

cp -- !(*.txt|*.c|*.py) /path/to/directory 
4

You can use find to get only files (regular ones only with -type f) that have no extension:

LC_ALL=C find . -maxdepth 1 ! -name '*.*' -type f 

So your copy command would be:

LC_ALL=C find . -maxdepth 1 ! -name '*.*' -type f -exec cp {} destination_folder/ \; 

Note that find (contrary to shell globs) does consider hidden files, but since those contain a . (at least one at the start), they won't be copied. For instance, neither .bashrc nor .file.conf will be copied as they both contain a . even if in the first case, the dot may not be seen as the extension delimiter. Changing the pattern to ?*.* would cause .bashrc to be copied and not .file.conf.

To avoid running one cp per file, on GNU systems:

LC_ALL=C find . -maxdepth 1 ! -name '*.*' -type f -exec cp -t destination_folder {} + 

On BSDs:

LC_ALL=C find . -maxdepth 1 -type f \! -name '*.*' -print0 | xargs -r0 -J {} cp {} destination_folder/ 

POSIXly:

LC_ALL=C find . ! -name . -prune ! -name '*.*' -type f -exec sh -c ' exec cp "$@" destination_folder/' sh {} + 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.