bash: list files that are not with a given extension - bash

I was wondering if there is a way to ls files in a folder that does not have a given extension? For example, if I have a folder full of .cpp and .h files, and I wanted to see if there are other types of files (such as config files and make files), how do I list or find?
Thanks,

You can use find:
find . -maxdepth 1 ! \( -name "*.cpp" -o -name "*.h" \)

shopt -s extglob
ls *!(.cpp|.h)

Pipe through an appropriate grep, e.g.:
ls | grep -Ev '\.(cpp|h)$'

Related

How can I diff two directories in bash recursively for only 1 file name?

Currently I am trying this:
diff -r /develop /us-prod
which shows all the differences between the two, but all I really care about here is a file named schema.json, which is guaranteed to be there in all directories, but this file can be different.
I want to diff these two directories, but only if the file name is schema.json.
I see that you can do -x to exclude files, but it is difficult to say which other files could be in there.
There are some guaranteed files to be there, but some are not. Is there more an "inclusion" than an exclude?
You can try this :
find /develop -type f -name schema.json -exec bash -c\
'diff "$1" "/us-prod${1#/develop}"' _ {} \;
Assuming the both directories have just one schema.json file for each directory
including their subdirectories, would you please try:
diff $(find /develop -type f -name schema.json) $(find /us-prod -type f -name schema.json)

How do I delete all the MP4 files with a file name not ending with -converted?

I converted/compressed several MP4 files from several folders using VLC.
The names of the converted/compressed files end with -converted, for example. 2. bubble sort-converted.mp4.
It's really cumbersome to go into each folder and delete all the original files and leave the converted files.
Using some zsh/bash command I'd like to recursively delete all the original files and leave the converted files.
For example I'll delete 3 - sorting/2. bubble sort.mp4 and will leave 3 - sorting/2. bubble sort-converted.mp4.
TLDR;
In easy words, delete all the files with .mp4 extension, where filesnames don't end with -converted using some zsh/bash command.
Also If there is some way to rename the converted file to the original name after deleting the original files, that will be a plus.
Thank you!
find can be used with a logical expression to match the desired files and delete them.
In your case the following can be used to verify whether it matches the files you want to delete. It finds all files that don't have converted in their names but do end in .mp4.
find . -type f -not \( -name '*converted*' \) -a -name "*.mp4"
Once you are satsified with the file list result then add -delete to do the actual delete.
find . -type f -not \( -name '*converted*' \) -a -name "*.mp4" -delete
Give this a try:
find . -name '*.mp4' | grep -v 'converted' | xargs rm -f
The zsh pure solution:
rm -f ^(*.mp4-converted)(.)
^ ................. negates
*-converted ....... pattern
(.) ............... regular files
Using gnu parallel (in case of many files)
parallel --no-notice rm -rf ::: ^(*converted)(.)
This will work even if your file names contain ', " or space:
find . -name '*.mp4' |
grep -v 'converted' |
parallel -X rm -f

Using find on multiple file extensions in combination with grep

I am having a problems using find and grep together in msys on Windows. However, I also tried the same command on a Linux machine and it behaved the same. Notwithstanding, the syntax below is for windows in that the semicolon on the end of the command is not preceded by a backslash.
I am trying to write a find expression to find *.cpp and *.h files and pass the results to grep. If I run this alone, it successfully finds all the .cpp and .h files:
find . -name '*.cpp' -o -name '*.h'
But if I add in an exec grep expression like this:
find . -name '*.cpp' -o -name '*.h' -exec grep -l 'std::deque' {} ;
It only greps the .h files. If I switch the .h and .cpp order in the command, it only searches the .h. Essentially, it appears to only grep the last file extension in the expression. What do I need to do to grep both .h and .cpp??
Since you're using -o, you will need to use parentheses around it:
find . \( -name '*.cpp' -o -name '*.h' \) -exec grep -l 'std::deque' {} \;
Or.. you can ...
bash$> grep '/bin' `find . -name "*.pl" -o -name "*.sh"`
./a.sh:#!/bin/bash
./pop3.pl:#!/usr/bin/perl
./seek.pl:#!/usr/bin/perl -w
./move.sh:#!/bin/bash
bash$>
Above command greps 'bin' in ".sh" and ".pl" files. And it has found them !!

How to delete a file except in any one of the subdirectory using shell script

Hi I want to delete a file from any of the subdirectories except one of the subdirectory.
For ex
folder a->a.txt
folder b->subdir 1 -> msgdir-> a.txt
folder c->
Now i want to delete a.txt only in folder a but not the file in msgdir .msgdir can be in any level of subdirectories as it would be changing.
Please help me to resolve this.
This will ignore specifically the msgdir at any level and remove a.txt except in msgdir.
find . ! -path '*/msgdir/*' -name a.txt -type f -delete
Tested with GNU find 4.4.2 and BSD find (Mac Yosemite).
The following approach is overkill if you have GNU find (or a newer BSD one), with the -path option. Otherwise, read on...
You haven't specified which shell you're using but if you have bash, you could go with something like this:
find -name a.txt -exec bash -c "[[ '{}' != */msgdir/* ]]" \; -print
This filters out paths containing /msgdir/, as the test will only pass if the file path doesn't contain the string. If you're happy with the results, you can change -print to -delete.
Without bash, you could use grep to determine the match:
find -name a.txt -exec sh -c "printf '%s' '{}' | grep -qv '/msgdir/'" \; -print

How to delete a file in any of the directories or subdirectories except one subdirectory

I want to delete a file from a directory which contains many subdirectories but the deletion should not happen in one subdiretory(searc) whose name is already predefined but path varies as shown below.So now how to delete a file i am using the below command
find . -type f -name "*.txt" -exec rm -f {} \;
this command deletes all the files in the directory.So How can we delete the file without serching that subdirectory.
The subdirectory file name will be same but the path will different
for eg
Main
|
a--> searc
|
b-->x--->searc
|
c-->y-->x-->searc
now the
the subdirectory not to be searched can be present any where as shown above
I think you want the -prune option. In combination with a successful name match, this prevents descent into the named directories. Example:
% mkdir -p test/{a,b,c}
% touch test/{a,b,c}/foo.txt
% find test -name b -prune -o -name '*.txt' -print
test/a/foo.txt
test/c/foo.txt
I am not completely sure what you're asking, so I can give only somewhat generic advice.
You already know the -name option. This refers to the filename only. You can, however, also use -wholename (a.k.a. -path), which refers to the full path (beginning with the one given as first option to find).
So if you want to delete all *.txt files except in the foo/bar subdirectory, you can do this:
find . -type f -name "*.txt" ! -wholename "./foo/bar/*" -delete
Note the -delete option; it doesn't require a subshell, and is easier to type.
If you would like to exclude a certain directory name regardless of where in the tree it might be, just don't "root" it. In the above example, foo/bar was "rooted" to ./, so only a top-level foo/bar would match. If you write ! -wholename "*/foo/bar/*" instead (allowing anything before or after via the *), you would exclude any files below any directory foo/bar from the operation.
You can use xargs instead of the exec
find .... <without the --exec stuff> | grep -v 'your search' | xargs echo rm -f
Try this first. If it is satisfactory, you can remove the echo.

Resources