Delete all not jpeg files

2

1

I have exercise, in which I have to delete all files, which are not jpeg.

I tried find -type f |xargs file| grep -iv 'jpeg', but it doesn't work.

diego9403

Posted 2015-08-15T06:17:22.753

Reputation: 807

1

possible duplicate of How to delete all files in a directory except some?

– LPChip – 2015-08-15T06:49:45.440

2

That question, How to delete all files in a directory except some?, discusses how to delete files based on the file's name. This question, by contrast, asks how to delete based on the file's type as reported by the file command.

– John1024 – 2015-08-15T06:54:43.293

Answers

7

Deleting based on file mimetype

To delete all non-jpeg regular files in the current directory or its subdirectories, use:

find . -type f -exec bash -c 'file -bi "$1" | grep -q image/jpeg || rm "$1"' none {} \;

This approach is safe for all file names. It will work even if the file names have newlines or other difficult characters in them.

How it works

  • find . -type f

    This starts a find command, restricting the files found to regular files, -type f.

  • -exec bash -c 'file -bi "$1" | grep -q image/jpeg || rm "$1"' none {} \;

    For all the files found, this runs a bash command to test the file's type. In particular, file -bi "$1" | grep -q image/jpeg will return true if file reports that the file has mimetype image/jpeg. The operator || assures that the rm command which follows is executed only for files which failed the jpeg test. Thus, all non-jpeg files are deleted.

Deleting based on file name

To delete all files whose names do not end in .jpeg:

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

This approach is also safe for all file names. It will work even if the file names have newlines or other difficult characters in them.

How it works

  • find .

    Find all files in the current directory and its subdirectories

  • -type f

    Restrict ourselves only to regular files

  • ! -name '*.jpeg'

    -name '*.jpeg' would find all files whose names end in .jpeg. The exclamation mark, !, however, means negation. So, ! -name '*.jpeg' restricts our search to files whose names do not end in .jpeg.

  • -delete

    This tells find to delete the files that match the above criteria.

Testing

To test the command, leave off the -delete:

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

This will show you what files would be deleted when the -delete action is used.

John1024

Posted 2015-08-15T06:17:22.753

Reputation: 13 893

No, no. There are no files "*.jpeg", they don't have format in name. I can know its name using 'file' command. – diego9403 – 2015-08-15T06:45:10.277

@adrian OK, OK. See updated answer. – John1024 – 2015-08-15T06:51:48.107

I didn't find answer. I have to add, that there are a lot of folders in folders, so "ls -l" is not enough.I thought about '-exec', but its accept only one commant and my favorite "|" doesn't work. – diego9403 – 2015-08-15T07:22:05.133

@adrian Look again: I did not use ls -l. I used find which will search all subfolders. Second, look at how I used -exec. The -exec command runs a bash shell and the bash shell fuilly supports features like | and ||. – John1024 – 2015-08-15T07:26:33.750

Ok, but I have to know what is the type of files ('jpeg'), that why i should use 'file', but that command make it difficult. After use 'file', i can't use rm to delete files. – diego9403 – 2015-08-15T07:53:07.143

@adrian I added an answer that uses file to determine the type. It is used in the -exec clause. If your browser doesn't show that, please reload the web page. The argument that I show for the -exec clause uses file to determine type and then executes rm according to the result. You say it is "difficult" but my answer shows how to do it. – John1024 – 2015-08-15T08:00:28.483

Thank you, my master. But I have some questions. What "$1" means. I changed it for "{}" and it works. However I want to know what is it. I used it in bash script, but I suspect is something different. – diego9403 – 2015-08-15T09:08:29.957

$1 means the same thing as in a script: it is the first argument. Our bash command looks like bash -c 'commands' none {}. The commands that are run can reference the value of {} as $1. Done this way, it is safe for all file names. If you change commands by replacing $1 with {}, then it will work for simple file names but it will fail if a difficult file name appears. So, don't do that. – John1024 – 2015-08-15T18:43:58.210

I never used "none". What that mean? – diego9403 – 2015-08-17T08:08:20.307

@adrian The none is critical for making the code work. When running bash -c 'commands' arg0 arg1 ..., bash interprets arg0 as the (pretend) name of the program that is being run and assigns it to $0. Next, arg1, the file name in our case, is assigned to $1. So, none is a placeholder: it is assigned to $0 which we never use but, without it, $1 would have the wrong value and the code would fail. – John1024 – 2015-08-17T18:42:48.740

Where did you learn to it? – diego9403 – 2015-08-21T14:19:20.467

@adrian One can learn a lot about bash/shell by reading the stackexchange sites and also Greg's FAQ.

– John1024 – 2015-08-21T18:03:57.653

Is it possibility to use mkdir with Pipeline? – diego9403 – 2015-08-22T06:58:23.683

@diego9403 Yes, particularly if used with xargs. – John1024 – 2015-08-22T07:23:51.343

Please, look http://superuser.com/questions/961036/copy-files-to-other-folder-find.

– diego9403 – 2015-08-22T09:21:26.003

I have to copy files (which are in lot of folders) to folder with its type. For example files lake.jpg (type jpeg) I have to copy to folder 'jpeg', but this folder is in other parent folder, which name is parametr in script. My command: find ./find -type f -exec bash -c ' file -b "$1"|cut -d " " -f 1 |awk -f wa|xargs cp "$1" ' none {} ; Files are copied, but there is an error: cp: ./find/PDF/20163.32630.27874' and find/PDF 20163.32630.27874' are the same file – – diego9403 – 2015-08-22T15:36:42.973