How can I write a GNU Makefile that has multiple target/prerequisites to execute the same recipe? - gnu-make

As an example:
a:b
cp $< $#
c:d
cp $< $#
e:f
cp $< $#
One solution would be to use a function:
define my_cp
cp $(1) $(2)
endef
a:b
$(call my_cp, $<, $#)
...
But I was wondering if people could suggest an alternative ...

The call thing seems more complex than necessary. You could just use:
CP = cp $< $#
a:b
$(CP)
...
You could also do this:
a c e:
cp $< $#
a: b
c: d
e: f
That's about it though.

Related

Bash delete all folders except one that might be nested

I am trying to work out a way to delete all folders but keep once, even if it is nested.
./release/test-folder
./release/test-folder2
./release/feature/custom-header
./release/feature/footer
If I run something like:
shopt -s extglob
rm -rf release/!(test-folder2)/
or
find ./release -type d -not -regex ".*test-folder2.*" -delete
get it OK, but in the cases when path is nested like feature/footer
Both command lines matches release/feature and it gets deleted.
Can you suggest any other option that would keep the folder, no matter how nested it is?
This is not best solution but it works.
# $1 = root path
# $2 = pattern
findex(){
# create temp dir
T=$(mktemp -d)
# find all dirs inside "$1"
# and save it in file "a"
find "$1" -type d >$T/a
# filtering file A by pattern "$2"
# and save it in file "b"
cat $T/a | grep "$2" >$T/b
# For each path in the file b
# add paths of the parent directories
# and save it in file "c"
cat $T/b | while read P; do
echo $P
while [[ ${#1} -lt ${#P} ]]; do
P=$(dirname "$P")
echo $P
done
done >$T/c
# make list in file "c" unique
# and save it in file "d"
cat $T/c | sort -u >$T/d;
# find from list "a" all the paths
# that are missing in the list "d"
awk 'NR==FNR{a[$0];next} !($0 in a)' $T/d $T/a
# remove temporary directory
rm -rf $T
}
# find all dirs inside ./path except matching "pattern"
# and remove it
findex ./path "pattern" | xargs -L1 rm
Test it
findex(){
T=$(mktemp -d)
find "$1" -type d >$T/a
cat $T/a | grep "$2" >$T/b
cat $T/b | while read P; do
echo $P
while [[ ${#1} -lt ${#P} ]]; do
P=$(dirname "$P")
echo $P
done
done >$T/c
cat $T/c | sort -u >$T/d;
# save result in file "e"
awk 'NR==FNR{a[$0];next} !($0 in a)' $T/d $T/a >$T/e
# output path of temporary directory
echo $T
}
cd $TMPDIR
for I in {000..999}; do
mkdir -p "./test/${I:0:1}/${I:1:1}/${I:2:1}";
done
T=$(findex ./test "5")
cat $T/a | wc -l # => 1111 dirs total
cat $T/d | wc -l # => 382 dirs matched
cat $T/e | wc -l # => 729 dirs to delete
rm -rf $T ./test

How to list the quantity of files per subdir on Unix

I have 60 subdirs in a directory, example name of the directory: test/queues.
The subdirs:
test/queues/subdir1
test/queues/subdir2
test/queues/subdir3
(...)
test/queues/subdir60
I want a command that gives me the output of the number of files in each subdirectory, listed separately, example:
test/queues/subdir1 - 45 files
test/queues/subdir2 - 76 files
test/queues/subdir3 - 950 files
(...)
test/queues/subdir60 - 213 files
Through my researchs, I only got the command ls -lat test/queues/* | wc -l, but this command outputs me the total of files in all of these subdirs. For example, It returns me only 4587, that is the total number of files in all these 60 subdirs. I want the output listing separately, the quantity of files in each folder.
How can I do that ?
Use a loop to count the lines for every subdirectory individually:
for d in test/queues/*/
do
echo "$d" - $(ls -lat "$d" | wc -l)
done
Note that the output of ls -lat some_directory will contain a few additional lines like
total 123
drwxr-xr-x 1 user group 0 Feb 26 09:51 ../
drwxr-xr-x 1 user group 0 Jan 25 12:35 ./
If your ls command supports these options you can use
for d in test/queues/*/
do
echo "$d" - $(ls -A1 "$d" | wc -l)
done
You can apply ls | wc -l in a loop to all subdirs
for x in *; do echo "$x => $(ls $x | wc -l)"; done;
If you want to restrict the output to directories that are one level deep and you only want a count of regular files, you could do:
find . -type d -maxdepth 1 -exec sh -c '
printf "%s\t" "$0"; find "$0" -type f -maxdepth 1 | wc -l' {} \; \
| column -t
You can get the "name - %d files" format with:
find . -type d -maxdepth 1 -exec sh -c '
printf "%s - %d files\n" "$0" \
"$(find "$0" -type f -maxdepth 1 | wc -l)"' {} \;
Using find and awk:
find test/queues -maxdepth 2 -mindepth 2 -printf "%h\n" | awk '{ map[$0]++ } END { for (i in map) { print i" - "map[i]} }'
Use maxdepth and mindepth to ensure that we are only searching the directory structure one level down. Print only the leading directories thorough printf "%h" Pipe the output into awk and create an incrementing map array with the directories as the index. At the end, loop through the map array printing the directories and the counts.
On Unix in the case of not -printf option with find, use exec dirname instead:
find test/queues -maxdepth 2 -mindepth 2 -exec dirname {} \; | awk '{ map[$0]++ } END { for (i in map) { print i" - "map[i]} }'

Compare two files and print only the unmatched values UNIX

I have two files suppose 1st.dat
a
b
c
d
and another file sppose 2nd.dat
d
e
f
g
my output should be like
a
b
c
e
f
g
I have tried using diff and sdiff but I am not getting the output as I mentioned. Please Help
You can use grep
grep -vf 2nd.dat 1st.dat > out.dat && grep -vf 1st.dat 2nd.dat >> out.dat
try diff like this:-
diff 1st.dat 2nd.dat|grep -e '<' -e '>'|sed -e 's/< \+//g' -e 's/> \+//g' > output.txt
cat output.txt
a
b
c
e
f
g
I think your version of uniq doesn't support the option --unique.
Can't harm to try:
cat 1st.dat 2nd.dat | sort | uniq --unique
This would be much easier than
cat 1st.dat 2nd.dat |grep -vf <(sort 1st.dat 2nd.dat | uniq -d)
A solution with grep -vf will need some more attention (matching substrings, empty lines). When you go for grep -vf the solution of #Daniel is easier to understand and modify, and Daniel doesn't use a slow sort.
You can use comm command in linux, like this comm -3 1st.dat 2nd.dat.
It will give you the desired output.
diff -c file1 file2 | grep '^- \|^+ ' | tr '+' ' ' | tr '-' ' '
file 1:
a
b
c
d
file 2:
d
e
f
g
output
a
b
c
e
f
g

Using bash shell on RHEL 7 - why does find find more files when I don't use -exec?

I'm looking for all setuid/setgid files.
When I don't use -exec, it works as expected:
# find /usr/bin -type f -perm -4000 -o -perm -2000
/usr/bin/wall
/usr/bin/ksu
/usr/bin/chage
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/fusermount
/usr/bin/passwd
/usr/bin/write
/usr/bin/su
/usr/bin/umount
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/pkexec
/usr/bin/crontab
/usr/bin/cgclassify
/usr/bin/cgexec
/usr/bin/ssh-agent
/usr/bin/Xorg
/usr/bin/at
/usr/bin/sudo
/usr/bin/locate
/usr/bin/staprun
When I use -exec, I only get a subset of the results back:
# find /usr/bin -type f -perm -4000 -o -perm -2000 -exec ls -l {} \;
-r-xr-sr-x. 1 root tty 15344 Jan 27 2014 /usr/bin/wall
-rwxr-sr-x. 1 root tty 19536 Aug 21 2015 /usr/bin/write
-rwxr-sr-x. 1 root cgred 15624 Sep 21 2014 /usr/bin/cgclassify
-rwxr-sr-x. 1 root cgred 15584 Sep 21 2014 /usr/bin/cgexec
---x--s--x. 1 root nobody 306304 Sep 24 2015 /usr/bin/ssh-agent
-rwx--s--x. 1 root slocate 40504 Jan 26 2014 /usr/bin/locate
Why?
You're only using -exec on the right-hand side of the -o. Thus, it's being parsed like this:
# What's actually happening
find /usr/bin '(' -type f -perm -4000 ')' -o '(' -perm -2000 -exec ls -l {} \; ')'
Obviously, that's not what you want.
To make it apply to both sides of the conditional, add some parens for grouping:
# What you want to happen
find /usr/bin -type f '(' -perm -4000 -o -perm -2000 ')' -exec ls -l {} +
The reason is that if you don't specify an explicit action, find assumes a -print as the default action. When you add an action yourself it turns off that default, so only the items for which you explicitly specify an action get one.
That is to say:
# These commands are all equivalent:
find /usr/bin -type f -perm -4000 -o -perm -2000
find /usr/bin '(' -type f -perm -4000 -o -perm -2000 ')' -print
find /usr/bin '(' '(' -type f -perm -4000 ')' -o '(' -perm -2000 ')' ')' -print
Note that last one, which exposes a caveat in the default behavior: You probably wanted the -type f to apply to both sides of the -o, but without explicit grouping it gets put on the left, just as an explicit -exec or print gets put on the right.
Moral of this story: When using -o in find, be explicit about your grouping unless you're very certain that the default behavior is what you want.

Gmake errors but only on certain Windows machines

I get the following error when I run my makefile in windows using gmake.
It happens on only 1 PC of 5 in the group - the other 4 run perfectly, and the file that's "not found" is definitely in the file system - I can run an assemble from the command line with the same path and it works fine.
C:\Eclipse\tools\gmake\gmake.exe BUILD_TYPE=RAM all
07:43:14 **** Build of configuration Debug for project U500 ****
"C:\\Eclipse\\tools\\gmake\\gmake.exe" BUILD_TYPE=RAM all
mkdir -p "object_flash"
mkdir -p "object"
mkdir -p "../TSP for iNav/Builds/iNav RAM/output"
mkdir -p "../TSP for iNav/Builds/Flash Release/output"
AS object/CpuCore.o
here is the curdir C:/work/Insulet/PhoenixII/robert_test_workspace/U500/Debug
C:/Eclipse/tools/codesourcery_arm_3.4.2/bin/arm-none-eabi-as -o object/CpuCore.o -gdwarf2 -meabi=4 -I"../../source/CPU" ../../source/CPU/CpuCore.s
Assembler messages:
**Can't open ../../source/CPU/CpuCore.s
for reading: Invalid argument**
The makefile is (look for #### for the rule causing an issue)
====
ifeq ($(BUILD_TYPE),RAM)
BUILDDIR = ../TSP for iNav/Builds/iNav RAM
MAPFILE = iNav_RAM.map
LDFILE = iNav_RAM.ld
IMGNAME = iNav_RAM.elf
DEBUGFLAGS = -DDEBUG_DEVELOPMENT_MODE
OBJDIR = ./object
DRIVERDIR =objects/ ``
#UT_OBJECTS = UnitTest.o
else
ifeq ($(BUILD_TYPE),FLASH)
BUILDDIR = ../TSP for iNav/Builds/FLASH Release
MAPFILE = FLASH_Release.map
LDFILE = FLASH_Release.ld
IMGNAME = FLASH_Release.elf
#POSTPROCESSING = sh -c 'pushd ../TSP\ for\ iNav/Batch\ Files/;\
cmd.exe /c "ProcessFlashReleaseImage.bat";\
popd'
#POSTPROCESSING = sh -c '$(OBJCOPY) -R .lcdmem -O binary -S $(IMG) $(APP_FLASH_IMG)'
#
# copy /b $(APP_FLASH_IMG) + $(UPGRADER_IMG) $(COMBINED_FLASH_IMG);\
# ../TSP\ for\ iNav/Build\ Tools/ProcessImage_iNavMainApp $(COMBINED_FLASH_IMG)'
APP_FLASH_IMG = "$(BUILDDIR)/Output/Pre_FLASH_Release.bin"
UPGRADER_IMG = "../TSP for iNav/UpgraderBin/Upgrader.bin"
COMBINED_FLASH_IMG = "$(BUILDDIR)/Output/FLASH_Release.bin"
OBJDIR = ./object_flash
OBJDIR1 = .\objects
#DEBUGFLAGS = -D__CSURF__
else
#This is to build the boot ROM
ifeq ($(BUILD_TYPE),FLASH_BOOT)
#### mods for boot flash needed
BUILDDIR = ../TSP for iNav/Builds/iNav Flash Boot
MAPFILE = BOOT_FLASH_Release.map
LDFILE = BOOT_FLASH_Release.ld
IMGNAME = BOOT_FLASH_Release.elf
#POSTPROCESSING = sh -c 'pushd ../TSP\ for\ iNav/Batch\ Files/;\
cmd.exe /c "ProcessFlashReleaseImage.bat";\
popd'
#POSTPROCESSING = sh -c '$(OBJCOPY) -R .lcdmem -O binary -S $(IMG) $(APP_FLASH_IMG)'
#
# copy /b $(APP_FLASH_IMG) + $(UPGRADER_IMG) $(COMBINED_FLASH_IMG);\
# ../TSP\ for\ iNav/Build\ Tools/ProcessImage_iNavMainApp $(COMBINED_FLASH_IMG)'
APP_FLASH_IMG = "$(BUILDDIR)/Output/Pre_FLASH_Release.bin"
UPGRADER_IMG = "../TSP for iNav/UpgraderBin/Upgrader.bin"
COMBINED_FLASH_IMG = "$(BUILDDIR)/Output/FLASH_Release.bin"
OBJDIR = ./object_flash
OBJDIR1 = .\objects
else
error:
#echo 'invalid build type: $(BUILD_TYPE)'
endif
endif
endif
IMG = "$(BUILDDIR)/Output/$(IMGNAME)"
#export C_COLON = /c
export C_COLON = /cygdrive/c
#export TOOL_LOCATION = $(C_COLON)/mgc/embedded/tools/codesourcery_arm_3.4.2/bin
export TOOL_LOCATION = C:/Eclipse/tools/codesourcery_arm_3.4.2/bin
export CC = $(TOOL_LOCATION)/arm-none-eabi-gcc
export AS = $(TOOL_LOCATION)/arm-none-eabi-as
export LD = $(TOOL_LOCATION)/arm-none-eabi-ld
export AR = $(TOOL_LOCATION)/arm-none-eabi-ar
export OBJCOPY = $(TOOL_LOCATION)/arm-none-eabi-objcopy
export RM = rm -f
export CP = cp
INCLUDDIRS = -I"../../source" -I"../../source/Drivers" -I"../../source/CPU" -I"../../source/smx/XFD" -I"../../source/smx/XFS" -I"../../source/smx/xusbd" -I"../../source/smx/xusbd/Core" -I"../../source/smx/xusbd/DCD" -I"../../source/smx/xusbd/Function" -I"."
CFLAGS = $(DEBUGFLAGS) -gdwarf-2 -mcpu=arm9 -fno-short-enums -fno-zero-initialized-in-bss -fsigned-char $(INCLUDDIRS) -Wall -Wno-missing-braces $(EXTRA_CFLAGS)
LDLIBS = --start-group "./TSP_for_iNav/CSL-ARM-GNU-Debug/Output/TSP_for_iNav.lib" "../TSP for iNav/GNU Libraries/libgcc.a" "../TSP for iNav/GNU Libraries/libc.a" --end-group
MAP = "$(BUILDDIR)/Output/$(MAPFILE)"
LINKSCRIPT = "./TSP_for_iNav/src/csgnu_arm/$(LDFILE)"
LDFLAGS = -Map $(MAP) -T$(LINKSCRIPT)
_APP_OBJECTS = alarm.o SdDiag.o alarm_repair.o beep.o cgmLog.o comm.o cond_state.o confirm.o confirm_calc.o confirm_pump.o conversion.o critical.o cursor_list.o diag.o display.o eeprom.o entry.o entry_bg.o font.o fooddb.o graph.o h_main.o handlers.o history.o history_page.o icons.o language.o language_Compiler_verify.o lcd.o list.o log.o logs.o mainloop.o menu.o pending.o prog_view.o pump.o pump_alert.o pump_cmd.o pumpmfg.o pumpverify.o queue.o ram.o rtc.o sched.o screen.o serial.o state.o state_alert.o state_bg_setup.o state_bgmeter.o state_bkgd_ck.o state_cgm.o state_comm.o state_fooddb.o state_presets.o state_sw.o suggbol.o suggbol_hist.o swtimer.o usb.o view.o view_bg.o
#APP_OBJECTS = $(patsubst %,$(OBJDIR)/%,$(_APP_OBJECTS))
APP_OBJECTS = $(addprefix $(OBJDIR)/,$(_APP_OBJECTS))
_DRIVER_OBJECTS = BGBoard.o BGMeter.o Flash.o init_lcd.o Interrupt.o MX21Config.o MX21_RTC.o MicroManager.o crc16-123.o eNavCGM.o gpio.o h_diag.o h_eeprom.o h_icons.o h_lcd.o h_rtc.o h_sys.o h_usb.o h_usbevt.o h_usbints.o h_usbos.o h_usbotg.o h_usbphy.o h_usbregs.o h_usbtrace.o hwTimer.o i2c.o key.o pwm.o rf.o secui.o spi.o super.o trans.o uart.o wdog.o
DRIVER_OBJECTS =$(addprefix $(OBJDIR)/,$(_DRIVER_OBJECTS))
_CPU_OBJECTS = AITC.o RunTimeInit.o
CPU_OBJECTS =$(addprefix $(OBJDIR)/,$(_CPU_OBJECTS))
_USB_OBJECTS = norfd.o norio_insulet.o fapi.o fcache.o fdnor.o fdram.o fdwin.o ffind.o fmount.o fpath.o fport.o funicode.o udhdw.o udinit.o uddcd.o uddevice.o udep0.o udfunc.o udutil.o udmx21.o udcompos.o udftempl.o udmouse.o udmstor.o udserial.o
USB_OBJECTS =$(addprefix $(OBJDIR)/,$(_USB_OBJECTS))
_ASM_OBJECTS = CpuCore.o CpuException.o
ASM_OBJECTS =$(addprefix $(OBJDIR)/,$(_ASM_OBJECTS))
OBJECTS = $(APP_OBJECTS) $(DRIVER_OBJECTS) $(CPU_OBJECTS) $(USB_OBJECTS) $(ASM_OBJECTS)
ARCHIVES = app.a Drivers.a CPU.a smx.a
.PHONY: all clean img TSP_lib
all: img
-include $(OBJECTS:.o=.d)
img: $(ASM_OBJECTS) $(ARCHIVES) TSP_lib
#echo LD $#
$(LD) -o $(IMG) $(ASM_OBJECTS) $(ARCHIVES) $(LDLIBS) $(LDFLAGS)
# $(POSTPROCESSING)
# #../TSP\ for\ iNav/Batch\ Files/ProcessFlashReleaseImage.bat
TSP_lib:
$(MAKE) -C "./TSP_for_iNav"
app.a: $(APP_OBJECTS)
#echo AR $#
$(AR) rc $# $(APP_OBJECTS)
Drivers.a: $(DRIVER_OBJECTS)
#echo AR $#
$(AR) rc $# $(DRIVER_OBJECTS)
CPU.a: $(CPU_OBJECTS)
#echo AR $#
$(AR) rc $# $(CPU_OBJECTS)
smx.a: $(USB_OBJECTS)
#echo AR $#
$(AR) rc $# $(USB_OBJECTS)
########### rule causing problems ###########
$(OBJDIR)/CpuCore.o: ../../source/CPU/CpuCore.s
-mkdir -p "object_flash"
-mkdir -p "object"
-mkdir -p "../TSP for iNav/Builds/iNav RAM/output"
-mkdir -p "../TSP for iNav/Builds/Flash Release/output"
#echo AS $#
#echo here is the curdir ${CURDIR}
$(AS) -o $# -gdwarf2 -meabi=4 -I"../../source/CPU" $<
$(OBJDIR)/CpuException.o: ../../source/CPU/CpuException.s
#echo AS $#
$(AS) -o $# -gdwarf2 -meabi=4 -I"../../source/CPU" $<
lcd.o: lcd.c
#echo CC $#
$(CC) $(CFLAGS) -O3 -c -o $# $<
#$(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/drivers/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/drivers/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/CPU/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/SMX/XFD/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/SMX/XFS/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/SMX/xusbd/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/SMX/xusbd/core/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/SMX/xusbd/DCD/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
$(OBJDIR)/%.o: ../../source/SMX/xusbd/Function/%.c
#echo CC $#
$(CC) $(CFLAGS) -c -o $# $<
# $(CC) -MM -MT '$(#:.o=.d) $#' $(CFLAGS) $< > $(<:.c=.d)
clean:
#echo CLEAN
rm -f $(OBJECTS)
rm -f ../../TSP\ for\ iNav/Builds/Flash\ Release/output/BOOT_FLASH_Release.elf
rm -f ../../TSP\ for\ iNav/Builds/Flash\ Release/output/BOOT_FLASH_Release.map
rm -f ../../TSP\ for\ iNav/Builds/Flash\ Release/output/FLASH_Release.elf
rm -f ../../TSP\ for\ iNav/Builds/Flash\ Release/output/FLASH_Release.map
rm -f ../../TSP\ for\ iNav/Builds/iNAV\ RAM/output/iNAV_RAM.map
rm -f ../../TSP\ for\ iNav/Builds/iNAV\ RAM/output/iNAV_RAM.elf
# del $(OBJECTS) $(OBJECTS:.o=.d) $(ARCHIVES) $(IMG)
# $(MAKE) clean -C "../../TSP for iNav"
cleanobj:
#echo CLEANOBJ
$(RM) $(OBJECTS)
Turns out there was something fishy on the guys path, so all is well now.

Resources