exclude file from rm in makefile - makefile

I have a makefile that has a clean PHONY like this:
.PHONY: clean
clean: clean_target
# Remove files created by the build process.
clean_target:
rm -rf *.mcs *.bit *.bin *.twr *.pwr *.tsi *.twx *.ncd *.pcf *.ngd *.ngc
I want to exclude a file named "FIFO.ngc" from being removed. How can I do that?
thanks,

If you're using GNU make you could do it like this:
clean_target:
rm -rf *.mcs *.bit *.bin *.twr *.pwr *.tsi *.twx *.ncd *.pcf *.ngd \
$(filter-out FIFO.ngc,$(wildcard *.ngc))

A bit lengthy, but you could remove the '*.ngc' from the list and add another line:
find . -type f -name '*.ngc' -not -name 'FIFO.ngc' -delete

Related

rm -rf /base-dir-path/*/work isn't the same as /base-dir-path/*/*/work

If I want to delete all subdirectories with a given name from a given root directory in linux/unix, you would think that you could just issue a command like:
rm -rf /base-dir-path/*/work
However, the above command will only go 1 directory deep when searching for any subdirectories named 'work'. To achieve what I want, I end up repeating the same command with an extra '*/' until the rm returns 'rm: No match.', EG:
rm -rf /base-dir-path/*/*/*/work
Is there a way to get commands like rm to match / in its wildcard search so that I only have to issue a single wildcard * character?
On tcsh 6.18.00 or newer:
set globstar
rm -rf /base-path/path/**/work
On bash 4.0 or newer:
shopt -s globstar
rm -rf /base-dir/path/**/work
On ksh:
set -o globstar # or set -G
rm -rf /base-dir/path/**/work
On zsh:
rm -rf /base-dir/path/**/work
Alternately, with a find compliant with the 2006 revision of POSIX:
find /base-dir/path -type d -name work -exec rm -rf -- '{}' +
If you don't have a find with -exec ... {} +, then you likely don't have an xargs -0 either, and need to do this the inefficient way to be safe:
find /base-dir/path -type d -name work -exec rm -rf -- '{}' ';'

Linux bash-script to run make in all subdirectories

I'm trying to write a bash-script in Linux which traverses the current directory and, in every subdirectory, it launches the existing makefile. It should work for each subdirectory, regardless of depth.
Some restrictions:
I cannot use Python;
I don't know in advance how many subdirectories and their names;
I don't know in advance the name of current directory;
the make command for each directory should only be launched if there is makefile in such folder.
Any ideas on how to do it?
Using -exec and GNU make
find -type f \( -name 'GNUmakefile' -o -name 'makefile' -o -name 'Makefile' \) \
-exec bash -c 'cd "$(dirname "{}")" && make' \;
Given that this is make-related. I'd try to use a makefile at the top-level instead of a script. Something like this:
MAKEFILES:=$(shell find . -mindepth 2 -name Makefile -type f)
DIRS:=$(foreach m,$(MAKEFILES),$(realpath $(dir $(m))))
.PHONY: all
all: $(DIRS)
.PHONY: $(DIRS)
$(DIRS):
$(MAKE) -C $#
I'd accept what #MLSC says about using for with find, and that kind of applies here too .. the problem with that is when you have a space in the directory name. However, in many cases that's not going to happen, and IMHO there are benefits in using a makefile instead of a script. (There might be a solution using make that can cope with spaces in the directory name, but I can't think of it off the top of my head.)
You can use this script https://gist.github.com/legeyda/8b2cf2c213476c6fe6e25619fe22efd0.
Example usage is:
foreach */ 'test -f Makefile && make'
This should work if dont care about the execution order or if parent directory also has a Makefile.
#!/bin/bash
for f in $(find . -name Makefile); do
pushd $(dirname $f)
make
popd
done

Searching Directories and Removing Folders and Files in Bash

I have a bash script that goes into a components/ and runs the following command:
cp -R vendor/* .
I then have a second command that traverses any folder, accept the vendor folder , inside the components directory lookinf got .git/, '.gitignore' and Documentation/ and removes them. How ever:
I don't thinks it's recursive
It doesn't actually remove those files and directories either because of the top point or because of permissions (should I add a sudo)?
A directory copied from vendor might look like:
something/
child-directory/
.git/ // -- Should be removed.
The command in question is:
find -name vendor -prune -o \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm - rf "{}" \; 2> /dev/null || true
Now if it is a permission error, I wont know about it because I want it to ignore any errors and continue with the script.
Any thoughts?
I think the problem is in the option -prune. Anyways, this might work for you...
find vendor -name '.git' -o -name '.gitignore' -o -name 'Documentation' | xargs rm -rf

Makefile: depend on every file of a directory

I'd like to do a Makefile that runs either with gnumake or makepp that packs all the files under given directiories:
DIRS:=$(shell find . -mindepth 2 -maxdepth 2 -not -name mp3 -not -name ".*" -type d)
PACKAGES = $(DIRS:%=%.npk)
all: packages
packages: $(PACKAGES)
%.npk: %/*
npack c $# #^
.PHONY: all packages
the problem is that there's no such thing as %/* in the dependencies.
I need the targets (X.npk) to depend on every file in directory X, but I don't know what the files are when I write the Makefile, 'cause they're generated later.
An example:
./dirA/x
./dirA/y
./dirB/e
./dirB/f
I'd like to create ./dirA.npk (depending on x,y), ./dirB.npk (e,f)
There's nothing I know about the dirs or the files in advance except that the find used in the 1st line finds all the dirs.
Try using the wildcard directive:
DEPS := $(foreach dir, $(DIRS), $(wildcard $(dir)/*))
%.npk: $(DEPS)
npack c $# $^
EDIT:
The above is just an example of using wildcard and makes each .npk file dependent on the files in all of the other folders. Your usage would be slightly different.
I think there may be an easier way to go about this. Why are you wanting to have a dependency on all of the files in the folder? Is it just to use the $^ operator? Or do you need to rebuild the .npk if any of the files changed?
One alternate (and possibly cleaner) solution would be to use the find utility in your recipe instead of $^ and use the .FORCE directive to always force the .npk file to be rebuilt. The downside is that .npk files may be rebuilt unnecessarily.
EDIT 2:
If there's not a way to do this cleanly with make commands, you can work around it by using .FORCE to ensure that the recipe is always run and move the "should I rebuild this file" check into the body of the recipe:
%.npk: .FORCE
check_for_rebuild.sh $# && npack c $# $^
where check_for_rebuild.sh is a shell script that does something like this:
#!/bin/bash
# Returns non-zero if the archive needs to be rebuilt
if [ -e $1 ]; then
folder_name=$(basename $1 .npk)
[ -z "$(find $folder_name -newer $1 -not -type d)" ] && return 0
fi
return 1
I don't really like that solution because it works around the problem instead of solving it directly, but it may be able to get you going in the meantime. If you are going to go that route, it's probably cleaner and easier to do everything in the shell script and either have the makefile simply invoke the script or get rid of the makefile entirely.
This is the solution I found:
it is based on the makedepend idea, with some "meta" scripting. Not very nice, but works.
PACKAGES :=
all: packages
-include Makefile.depend
packages: Makefile.depend $(PACKAGES)
depend: clean Makefile.depend
Makefile.depend:
#(PACKAGES= ; \
for DIR in `find . -mindepth 2 -maxdepth 2 -not -name mp3 -not -name ".*" -type d` ; \
do \
PACKAGE=`basename $${DIR}.npk` ; \
PACKAGES="$${PACKAGES} $${PACKAGE}" ; \
DEPS=`find $${DIR} -not -type d | sed -e 's#\([: ]\)#\\\\\1#' -e 's#^\./\(.*\)# \1#' | tr -d "\n"` ; \
SUBDIR=`echo $${DIR} | sed -e 's#^\./\([^/]\+\)/.*#\1#'` ; \
FILES=`echo \ $${DEPS} | sed -e "s# $${SUBDIR}/# #g"` ; \
echo "$${PACKAGE}:$${DEPS}" ; \
echo " #cd $${SUBDIR} ; \\" ; \
echo " npack c ../\$$# $${FILES} ; \\" ; \
echo ; \
done ; \
echo "PACKAGES = $${PACKAGES}" \
)>> Makefile.depend ; \
cleanall: clean
rm -f *.npk
clean:
#rm -f Makefile.depend
.PHONY: all packages depend clean
With makepp you can do this in 2 steps, via the :foreach rule modifier:
$(foreach).txt: $(foreach)/*: foreach */
&echo $(inputs) -o $(output)
This provides a rule for every subdirectory, which reexecutes whenever there is a change in the list of files therein.

How do I remove all .pyc files from a project?

I've renamed some files in a fairly large project and want to remove the .pyc files they've left behind. I tried the bash script:
rm -r *.pyc
But that doesn't recurse through the folders as I thought it would. What am I doing wrong?
find . -name "*.pyc" -exec rm -f {} \;
find . -name '*.pyc' -type f -delete
Surely the simplest.
Add to your ~/.bashrc:
pyclean () {
find . -type f -name "*.py[co]" -delete
find . -type d -name "__pycache__" -delete
}
This removes all .pyc and .pyo files, and __pycache__ directories. It's also very fast.
Usage is simply:
$ cd /path/to/directory
$ pyclean
In current version of debian you have pyclean script which is in python-minimal package.
Usage is simple:
pyclean .
If you're using bash >=4.0 (or zsh)
rm **/*.pyc
Note that */*.pyc selects all .pyc files in the immediate first-level subdirectories while **/*.pyc recursively scans the whole directory tree. As an example, foo/bar/qux.pyc will be deleted by rm **/*.pyc but not by */*.pyc.
The globstar shell options must be enabled. To enable globstar:
shopt -s globstar
and to check its status:
shopt globstar
For windows users:
del /S *.pyc
I used to use an alias for that:
$ which pycclean
pycclean is aliased to `find . -name "*.pyc" | xargs -I {} rm -v "{}"'
find . -name '*.pyc' -print0 | xargs -0 rm
The find recursively looks for *.pyc files. The xargs takes that list of names and sends it to rm. The -print0 and the -0 tell the two commands to seperate the filenames with null characters. This allows it to work correctly on file names containing spaces, and even a file name containing a new line.
The solution with -exec works, but it spins up a new copy of rm for every file. On a slow system or with a great many files, that'll take too long.
You could also add a couple more args:
find . -iname '*.pyc' -print0 | xargs -0 --no-run-if-empty rm
iname adds case insensitivity, like *.PYC . The no-run-if-empty keeps you from getting an error from rm if you have no such files.
$ find . -name '*.pyc' -delete
This is faster than
$ find . -name "*.pyc" -exec rm -rf {} \;
Further, people usually want to remove all *.pyc, *.pyo files and __pycache__ directories recursively in the current directory.
Command:
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
Django Extension
Note: This answer is very specific to Django project that have already been using Django Extension.
python manage.py clean_pyc
The implementation can be viewed in its source code.
Just to throw another variant into the mix, you can also use backquotes like this:
rm `find . -name *.pyc`
full recursive
ll **/**/*.pyc
rm **/**/*.pyc
Now there is a package pyclean on PyPI, which is easy to use, and cross-platform. User just need a simple command line to clean all __pycache__ files in current dir:
pyclean .
if you don't want .pyc anymore you can use this single line in a terminal:
export PYTHONDONTWRITEBYTECODE=1
if you change your mind:
unset PYTHONDONTWRITEBYTECODE
First run:
find . -type f -name "*.py[c|o]" -exec rm -f {} +
Then add:
export PYTHONDONTWRITEBYTECODE=1
To ~/.profile
rm -r recurses into directories, but only the directories you give to rm. It will also delete those directories. One solution is:
for i in $( find . -name *.pyc )
do
rm $i
done
find will find all *.pyc files recursively in the current directory, and the for loop will iterate through the list of files found, removing each one.
find . -name "*.pyc"|xargs rm -rf
If you want to delete all the .pyc files from the project folder.
First, you have
cd <path/to/the/folder>
then find all the .pyc file and delete.
find . -name \*.pyc -delete
You can run find . -name "*.pyc" -type f -delete.
But use it with precaution. Run first find . -name "*.pyc" -type f to see exactly which files you will remove.
In addition, make sure that -delete is the last argument in your command. If you put it before the -name *.pyc argument, it will delete everything.
To delete all the python compiled files in current directory.
find . -name "__pycache__"|xargs rm -rf
find . -name "*.pyc"|xargs rm -rf
If you want remove all *.pyc files and __pycache__ directories recursively in the current directory:
with python:
import os
os.popen('find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf')
or manually with terminal or cmd:
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
py3clean works for me!
cd /usr/local/lib/python3.9
sudo py3clean -v .
Had to add a few ignore params on M1:
pyclean --verbose . --ignore "Library",".Trash"

Resources