I created a folder on my home directory call junk, and let's say I want to move all .cpp and .h files to it. How would I do it? My first thought is to start with find ~ -name *.cpp -print, but I don't know how to put in multiple patterns into the find argument, and I'm fairly lost after that.
3 Answers 3
portably:
cd &&
find . -path ./junk -prune -o -type f \( \
-name '*.h' -o -name '*.cpp' \) -exec sh -c '
exec mv -i "$@" junk' sh {} +
Above excluding the junk
folder itself from the search.
We're only removing regular files (-type f
). There may be other types of files you want to move like symlinks, but beware that moving symlinks often break them.
The -i
is a safeguard to avoid two files with the same name overriding each other.
-
please once check my updated answer, I think I have wrongly explain regex partRahul Patil– Rahul Patil2014年02月08日 11:57:36 +00:00Commented Feb 8, 2014 at 11:57
-
Could you please explain the extra calls to
sh
? As opposed to for instancefind . ! -path './junk/*' -type f \( -name '*.h' -o '*.cpp' \) -exec mv -i "{}" ./junk/ \;
grebneke– grebneke2014年02月08日 12:12:28 +00:00Commented Feb 8, 2014 at 12:12 -
@grebneke,
mv -i {} junk \;
would run onemv
per file. Using+
means pass as may files as possible. You needsh
to be able to have ajunk
argument after that list. With GNU or FreeBSDmv
, you could have done-exec mv -it junk {} +
instead.Stéphane Chazelas– Stéphane Chazelas2014年02月08日 12:43:26 +00:00Commented Feb 8, 2014 at 12:43 -
@StephaneChazelas - I see, but there are two
sh
, what does the second one dosh {} +
?grebneke– grebneke2014年02月08日 13:13:15 +00:00Commented Feb 8, 2014 at 13:13 -
@grebneke, the first argument after
sh -c code
is for0ドル
(used for error messages...),"$@"
starts after.Stéphane Chazelas– Stéphane Chazelas2014年02月08日 14:44:33 +00:00Commented Feb 8, 2014 at 14:44
If on a GNU system, you can use the -regex
option to find
as shown below:
find . -regex ".*\.\(h\|cpp\)" -exec echo mv -v "{}" ~/junk \;
the output will show which command would be executed, like a dry run. If that looks good, you can remove the echo
for applying.
Command Break Down
-regex
: File name matches regular expression pattern, the default regex type it's usesemacs
".*\.\(h\|cpp\)"
: Since it's uses default regex typeemacs
, as per pattern match.
(dot) means matches any character so to match exact.
( dot), we have to use escape character that is\
. means for special character like(
,|
we have to use escape character. the pattern same as.*.(h|cpp)
(regextype posix-egrep )-exec
: Execute command{ }
: The string { } replaced by the matches file name\;
: Needs to be there as it tells the end of arguements provided to -exec variable
For more information on regular expression you can refer
man 7 regex
- Regex Tutorial
-
can you break down what ".*\.(h\|cpp)" means? I'm a beginner so I'm completely lost.Jonathan Chiou– Jonathan Chiou2014年02月08日 11:33:55 +00:00Commented Feb 8, 2014 at 11:33
-
@JonathanChiou See the updated answer..Rahul Patil– Rahul Patil2014年02月08日 11:50:39 +00:00Commented Feb 8, 2014 at 11:50
According to pinfo bash
->Shell Expansions->Filename Expansion->3.5.8.1 Pattern Matching, the ‘extglob’ shell option may be enabled using the ‘shopt’ builtin. Apparently, Cargo
, Rust's package manager and build tool also enables this in their bash completion script with shopt -s extglob
. So my shell already recognizes several extended pattern matching operators. Lists of patterns can separated by a ‘|’.
‘?(PATTERN-LIST)’ Matches zero or one occurrence of the given patterns.
‘*(PATTERN-LIST)’ Matches zero or more occurrences of the given patterns.
‘+(PATTERN-LIST)’ Matches one or more occurrences of the given patterns.
‘@(PATTERN-LIST)’ Matches one of the given patterns.
‘!(PATTERN-LIST)’ Matches anything except one of the given patterns.
So we can do something like this.
mkdir -p ~/junk
for name in *.?(h|cpp); do echo mv -- "${name}" ~/junk/; done
mv -- ggml-alloc.h ~/junk/
mv -- ggml-backend.h ~/junk/
mv -- ggml-backend-impl.h ~/junk/
mv -- ggml-cuda.h ~/junk/
mv -- ggml.h ~/junk/
mv -- ggml-impl.h ~/junk/
mv -- ggml-metal.h ~/junk/
mv -- ggml-mpi.h ~/junk/
mv -- ggml-opencl.cpp ~/junk/
mv -- ggml-opencl.h ~/junk/
mv -- ggml-quants.h ~/junk/
mv -- llama.cpp ~/junk/
mv -- llama.h ~/junk/
mv -- unicode.h ~/junk/
And then remove the echo
, if it purports to do what we want...