I wrote this code a few months ago and didn't touch it again. Now I picked it up to complete it. This is part of a larger script to find all files with specific extensions, find which ones have a certain word, and replace every instance of that word with another one.
In this excerpt, ARG4 is the directory it starts looking at (it keeps going recursively).
ARG2 is the word it looks for.
ARG3 is the word that replaces ARG2.
ARG4="$4"
find -P "$ARG4" -type f -name '*.h' -o -name '*.C' \
-o -name '*.cpp' -o -name "*.cc" \
-exec grep -l "$ARG2" {} \; | while read file; do
echo "$file"
sed -n -i -E "s/"$ARG2"/"$ARG3"/g" "$file"
done
Like I said it's been a while, but I've read the code and I think it's pretty understandable. I think the problem must be in the while loop. I googled more info about "while read ---" but I didn't find much.
EDIT 2: See my answer down below for the solution.
I discovered that find wasn't working properly. It turns out that it's because of -maxdepth 0 which I put there so that the search would only happen in the current directory. I took it out, but then the output of find was one single string with all of the file names. They needed to be separate entities so that the while loop could read each one. So I rewrote it:
files=(`find . -type f \( -name "*.h" -o -name "*.C" -o \
-name "*.cpp" -o -name "*.cc" \) \
-exec grep -l "$ARG1" {} \;`)
for i in ${files[#]} ; do
echo $i
echo `gsed -E -i "s/$ARG1/$ARG2/g" ${i}`
done
I had to install GNU sed, the regular one just wouldn't accept the file names.
It's hard to say if this is the only issue, since you haven't said precisely what's wrong. However, your find command's -exec action is only being applied for *.cc files. If you want it to apply for any of those, it should look more like:
ARG4="$4"
find -P "$ARG4" -type f \( -name '*.h' -o -name '*.C' \
-o -name '*.cpp' -o -name "*.cc" \) \
-exec grep -l "$ARG2" {} \; | while read file; do
echo "$file"
sed -n -i -E "s/"$ARG2"/"$ARG3"/g" "$file"
done
Note the added ( and ) for grouping to attach the action to the result of all of those.
So im trying to create a script that looks in a folder and finds all the file types that have .cpp and run g++ on them. so far i have but it doesn't run it says unexpected end
for i in `find /home/Phil/Programs/Compile -name *.cpp` ; do echo $i ;
done
Thanks
The problem with your code is that the wildcard * is being expanded by the shell before being passed to find. Quote it thusly:
for i in `find /home/Phil/Programs/Compile -name '*.cpp'` ; do echo $i ; done
xargs as suggested by others is a good solution for this problem, though.
find has an option for doing exactly that:
find /p/a/t/h -name '*.cpp' -exec g++ {} \;
This code works for me:
#!/bin/bash
for i in `find /home/administrator/Desktop/testfolder -name *.cpp` ; do echo $i ;
done
I get:
administrator#Netvista:~$ /home/administrator/Desktop/test.sh
/home/administrator/Desktop/testfolder/main.cpp
/home/administrator/Desktop/testfolder/main2.cpp
You could use xargs like:
find folder/ -name "*.cpp" | xargs g++
Or if you want to handle files which contain whitespaces:
find folder/ -name "*.cpp" -print0 | xargs -0 g++
I think you want to use xargs:
For example:
find /home/Phil/Programs/Compile -name *.cpp | xargs g++
How about using xargs like this:
find $working_dir -type f -name *.cpp | xargs -n 1 g++
I'm trying to integrate checking my code using pyflakes into a building process. I've defined the following target in my Makefile:
pyflakes:
find $(APPLICATION_DIRECTORY) -iname "*.py" -exec pyflakes "{}" \;
The problem is that find returns 0 every time even if there are code issues (pyflakes returns not 0) and make succeeds. Ideally, I want to run the check on every source file and stop make if at least one of -exec failed. Is there a way to achieve this?
I assume there is no way to make find return exit code of -exec.
What should work is piping to xargs:
find $(APPLICATION_DIRECTORY) -iname "*.py" |xargs -I file pyflakes file
You can just pipe the output of find to your own processing loop and exit when pyflakes returns an exit status other than 0.
find . -iname '*.jpg' | \
while read line ; do
pyflakes "$line"
res=$?
if [ $res -ne 0 ] ; then
exit $res
fi
done
Make it end the find process by
pyflakes:
find $(APPLICATION_DIRECTORY) -iname "*.py" -exec bash -c 'pyflakes {}; if [[ $$? != 0 ]]; then kill -INT $$PPID;fi' \;
This is what goes into the makefile, it is not a script file, if you wonder about the syntax.
I have this bash script here
#!/bin/bash
find /Users/ -name "*.mov" -o -name "*.flv" -o -name "*.mp4" -o -name "*.avi" -o -name "*.wmv" -o -name "*.mpeg" -o -name "*.avi" -o -name "*.wmv" -o -name "*.f4v" -o -name "*.m4v" -o -name "*.mxf" -o -name "*.ts" -type f -mtime +7 -exec rm -rf {} \;
It finds all the files that are older than 7 days, and that works fine, but when I want it to remove the result set that I found it doesn't delete any of the files. Is there something I'm doing wrong? This is on Mac OSX 10.6
Any help would be great. Thanks!
Instead, of -exec rm -rf {}\;, try the -delete option if it's available on your version of the find command. This will show an error message after each failed attempt to delete. That might give you more information what's going on.
$ find . -name "*.foo" -type f -mtime +7 -delete
find: -delete: unlink(./four.foo): Permission denied
find: -delete: unlink(./one.foo): Permission denied
find: -delete: unlink(./three.foo): Permission denied
find: -delete: unlink(./two.foo): Permission denied
Neither find is returning the actual exit code from the delete/rm command. You may want to do something like this:
find . -name ... -type f -mtime +7 | while read file
do
if rm -fr $file
then
echo "Successfully deleted $file"
else
echo "Error deleting file: Exit code $?"
fi
done
That might give you a better understanding of what's going on.
Maybe you should run the command with sudo ? You may not have full access to all directories as a normal user.
The find command is in /usr/bin, which isn't in the default PATH for cron jobs. Either run it as /usr/bin/find, or set PATH at the beginning of your script.
Is there a way to determine how many lines of code an Xcode project contains? I promise not to use such information for managerial measurement or employee benchmarking purposes. ;)
I see this floating around and use it myself:
find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.swift" ")" -print0 | xargs -0 wc -l
Check out CLOC.
cloc counts blank lines, comment lines, and physical lines of source code in many programming languages.
(Legacy builds are archived on SourceForge.)
I have been using CLOC as mentioned by Nathan Kinsinger and it is fairly easy to use. It is a PERL script that you can add and run from your project directory.
PERL is already part of Mac OS and you can invoke the script this way to find out your number of lines you have written:
perl cloc-1.56.pl ./YourDirectoryWhereYourSourcesAre
This is an example of output i got from such command:
176 text files.
176 unique files.
4 files ignored.
http://cloc.sourceforge.net v 1.56 T=2.0 s (86.0 files/s, 10838.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Objective C 80 3848 1876 11844
C/C++ Header 92 980 1716 1412
-------------------------------------------------------------------------------
SUM: 172 4828 3592 13256
-------------------------------------------------------------------------------
Open up Terminal.app, go into your project's root directory, and run this command:
For Swift only:
find . \( -iname \*.swift \) -exec wc -l '{}' \+
For Obj-C only:
find . \( -iname \*.m -o -iname \*.mm -o -iname \*.h \) -exec wc -l '{}' \+
For Obj-C + Swift:
find . \( -iname \*.m -o -iname \*.mm -o -iname \*.h -o -iname \*.swift \) -exec wc -l '{}' \+
For Obj-C + Swift + C + C++:
find . \( -iname \*.m -o -iname \*.mm -o -iname \*.c -o -iname \*.cc -o -iname \*.h -o -iname \*.hh -o -iname \*.hpp -o -iname \*.cpp -o -iname \*.swift \) -exec wc -l '{}' \+
Terminal quick tips:
ls: list directory contents
cd: change directory
Press tab to autocomplete
Remember to put "\" backslash before spaces
I suggest going one folder down from the main project so you get rid of code count from the frameworks
In terminal, change into the project directory and run:
find . -type f -print0 | xargs -0 cat | wc -l
If you want only certain file types, try something like
find . -type f -name \*.[ch]* -print0 | xargs -0 cat | wc -l
open terminal
navigate to your project
execute following command inside your project:
find . -path ./Pods -prune -o -name "*.swift" -print0 ! -name "/Pods" | xargs -0 wc -l
Or:
find . -path ./Pods -prune -o -name "*[hm]" -print0 ! -name "/Pods" | xargs -0 wc -l
(*Excluding pod files count from total count)
Check out Xcode Statistician, it does exactly what you want. It also provides other interesting statistics so is worth a run for fun now and then.
Note that it will not look inside real folders, though it will look in groups. Odds are you aren't using real folders so it'll work great. If you are using folders then you just have to do the count in each folder and add them together.
Note: As of June, 2012, it seems this does not work properly with the latest versions of Xcode.
If you go to your project's directory in terminal and enter:
find . "(" -name "*.h" -or -name "*.m" -or -name "*.mm" -or -name "*.hpp" -or -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.swift" ")" -print0 | xargs -0 wc -l
That will give you a project breakdown, as well as the line total for each file and the project as a whole.
Steps to implement CLOC library in Mac as below:
Open Terminal.
Install Homebrew by copying and pasting the below command in the Terminal (including double quotes).
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Enter system password if asked.
You will see the terminal screen as below.
System will popup so many permissions, allow all the permissions
If everything goes fine, you will see terminal screen as below,
Now its time to install CLOC using below command.
brew install cloc
Navigate to the project directory and run either of the following commands.
cloc . --exclude-dir=Pods (to exclude pod files)
cloc . (including pod files)
If everything goes fine, it will display the number of lines of code as below,
Nozzi's version doesn't work for me, but this one:
find . -type f -print0 | xargs -0 cat | wc -l
A quick & easy way:
Use a regex search (Find Navigator, choose Find > Regular Expression).
.\n
Works conveniently with Xcode search scopes and you can easily customize it to whatever type of line you'd like to count ;).
You can install SLOCCount through MacPorts. Or, more crudely, you can use wc -l.
I am not familiar with xcode, but if all you need is to count the number of lines from all those specific files within a directory tree, you may use the following command:
find .... match of all those files ... -exec wc -l {} +
Following Joshua Nozzi's answer, in GNU find the regular expression for such files would be like:
find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.swift" ")" -exec wc -l {} +
or even
find -regex ".*\.\(m\|mm\|cpp\|swift\)$" -exec wc -l {} +
this uses a regular expression to match all files ending in either .m, .mm, .cpp or .swift. You can see more information about those expressions in How to use regex in file find.
If you are working with Mac OS find, then you need a slightly different approach, as explained by Motti Shneor in comments:
find -E . -regex ".*\.([hmc]|mm|cp+|swift|pch)$" -exec wc -l {} +
Both will provide an output on the form of:
234 ./file1
456 ./file2
690 total
So you can either keep it like this or just pipe to tail -1 (that is, find ... | tail -1) so that you just get the last line being the total.
line-counter is a good alternative. It's lighter than CLOC and much more powerful and easier to use than other commands.
A quick overview
This is how you get the tool
$ pip install line-counter
Use line command to get the file count and line count under current directory (recursively)
$ line
Search in /Users/Morgan/Documents/Example/
file count: 4
line count: 839
If you want more detail, just use line -d.
$ line -d
Search in /Users/Morgan/Documents/Example/
Dir A/file C.c 72
Dir A/file D.py 268
file A.py 467
file B.c 32
file count: 4
line count: 839
And the best part of this tool is, you can add .gitignore like configure file to it. You can set up rules to select or ignore what kind of files to count just like what you do in '.gitignore'. Yes, this tool is just invented to make knowing how many lines I have easier.
More description and usage is here: https://github.com/MorganZhang100/line-counter
I'm the author of this simple tool. Hope it can help somebody.