2

Trying to get this working in CentOS and bash:

  1. search for all mp4, mkv, avi recursively
  2. delete that file and replace with empty file with the same name
terdon
  • 242,166

2 Answers2

7

To find the files use find. To truncate the file use truncate. I am also using xargs to call upon truncate. However you could use the -exec option of find to avoid using xargs.

So something like this should work. (untested)

find . \( -iname '*.mkv' -o -iname '*.avi' -o -iname '*.mp4' \) -print0 | xargs -0 echo truncate -s 0

Remove the echo after testing that it outputs the correct commands, with correct file-names.

terdon
  • 242,166
  • 1
    Although technically correct, combining find, xargs and truncate seems dangerous. Anyone unfamiliar with any of those tools should further educate themselves before copy-pasting this. Building an equivalent of rm -rf * by accident is all too easy. – j2L4e Oct 29 '20 at 13:21
  • While the same generally applies to the globstar + loop approach from @terdon it seems to be much easier to reason about. – j2L4e Oct 29 '20 at 13:30
6

You can use the globstar option of bash which enables the ** glob character:

globstar
    If set, the pattern ** used in a pathname expansion con‐
    text will match all files and zero or  more  directories
    and  subdirectories.  If the pattern is followed by a /,
    only directories and subdirectories match.

With that, you can use **/*.mkv to recursively find all files or directories whose name ends with .mkv. Next, don't think of this as deleting the original and creating a new file. All you need to do is empty the original file. The simplest way to do that is > file. That will open the file for writing, overwriting anything that was already there. Since you don't actually write anything, it will result in an empty file.

With that in mind, consider the following example:

$ tree -h
.
├── [4.0K]  dir1
│   ├── [4.0K]  subdir1
│   │   ├── [ 48K]  file.mp3
│   │   └── [ 53M]  file.mp4
│   └── [4.0K]  subdir2
│       └── [136M]  file2.avi
├── [4.0K]  dir2
│   ├── [399K]  file.mkv
│   └── [4.0K]  subdir1
│       └── [548M]  file3.avi
└── [ 30M]  file.avi

5 directories, 6 files

We have 6 files, 5 of which match the pattern you are looking for (dir1/subdir1/file.mp3 should not be changed). To empty the files that match the pattern you gave, you just need to do this:

$ shopt -s globstar 
$ for f in **/*.mp4 **/*.avi **/*.mkv; do > "$f"; done

if we now run tree again, you will see that all files except the mp3 one have been emptied:

$ tree -h
.
├── [4.0K]  dir1
│   ├── [4.0K]  subdir1
│   │   ├── [ 48K]  file.mp3
│   │   └── [   0]  file.mp4
│   └── [4.0K]  subdir2
│       └── [   0]  file2.avi
├── [4.0K]  dir2
│   ├── [   0]  file.mkv
│   └── [4.0K]  subdir1
│       └── [   0]  file3.avi
└── [   0]  file.avi

Alternatively, you can use find as ctrl-alt-delor suggested, but there's no need for xargs or -print0 or any of that. Simply do:

find . \( -name '*.mkv' -o -name '*.avi' -o -name '*.mp4' \) -exec sh -c ' > "$1"' mysh {} \;
marcelm
  • 2,485
terdon
  • 242,166