order of operations: erase old files before building new ones - makefile

Although I though I was pretty good with makefiles, I have a problem I just can't solve about order of commands in a makefile.
Lets detail.
Say I have some program that produces some files of type "a". I want to manually take these and process them through some tool that takes as input one "a" file and produces a file of type "b".
So my makefile holds the following pattern rule:
%.b:%.a
$(MYTOOL) $< >$#
I gather all the files to build in a variable B_FILES, build from the list of "a" files:
A_FILES = $(wildcard *.a)
B_FILES = $(patsubst %.a,%.b,$(A_FILES))
And this is called through a general call target:
build_b_files: $(B_FILES)
#echo "done!"
Works perfectly.
Now the problem: each run of the main program can generate a varying number of "A" files, with some common naming scheme (say file_0.a, file_1.a, file_2.a, ...).
But if a run produces 20 files, and the following only 10, then I still have the remaining 10 files from latter run present.
So what I want to do is make my build_b_files target automatically erase all the old "b" file before building the new ones.
I tried to use the order-only prerequisite, but the following fails: it just rebuilds every time all the files, then erases them (!).
erase_all_B:
#rm *.b
build_b_files: $(B_FILES) | erase_all_B
#echo "- Done target $#"
I am probably misunderstanding something about this concept of "order-only".
How can I achieve this goal ?
Edit: to clarify question, see the following (simulated) session demonstrating what I am looking for (ls only showing relevant files here):
$ myapp some-arguments... (will produce 4 'a' files)
$ ls -l (stripped)
june 8 16:00 file_0.a
june 8 16:00 file_1.a
june 8 16:00 file_2.a
june 8 16:00 file_3.a
$ make build_b_files
$ ls -l
june 8 16:00 file_0.a
june 8 16:00 file_1.a
june 8 16:00 file_2.a
june 8 16:00 file_3.a
june 8 16:00 file_0.b
june 8 16:00 file_1.b
june 8 16:00 file_2.b
june 8 16:00 file_3.b
.... (some time) ....
$ myapp some-other-arguments... (will produce only 3 'a' files)
$ ls -l
june 8 17:00 file_0.a
june 8 17:00 file_1.a
june 8 17:00 file_2.a
june 8 16:00 file_3.a
june 8 16:00 file_0.b
june 8 16:00 file_1.b
june 8 16:00 file_2.b
june 8 16:00 file_3.b
$ make build_b_files
$ ls -l
june 8 17:00 file_0.a
june 8 17:00 file_1.a
june 8 17:00 file_2.a
june 8 17:00 file_0.b
june 8 17:00 file_1.b
june 8 17:00 file_2.b
(For those who wonder, this is about graphviz, that generates images from dot files...)

You need to erase all b files before remaking any b files, so what you're saying is that erase_all_B should be a prerequisite of the $(BFILES) themselves, not build_b_files:
.PHONY: erase_all_B
erase_all_B: ; $(RM) *.b
$(B_FILES): erase_all_B
Test with the following
all: bar baz
bar baz: foo
ba%:
#echo bar baz
foo:
#echo foo

If the tool that produces .a files removes the old ones, you can build a "list of .b files to remove" easily with something like:
TO_REMOVE := $(filter-out $(B_FILES),$(wildcard *.b))
And if the tool that produces .a files does not remove older ones, why removing matching .b files? They will be regenerated, as .a files are still here. And if .a files are modified, corresponding .b files will be regenerated by make (as being out of date).

Related

Automating a roster with bash

I have to create a cleaning roster for an appartment building and would like to automate it with GNU bash if possible.
Requirements:
The tenants have to clean the corridor on their floor every week.
The cycle starts on Feb. 11, 2019 and lasts for 30 weeks (10x3).
There are 4 floors to my building.
There are 10 tenants capable of doing the task per floor.
The names of the tenants are in the 3rd column of the file tenants.csv, (sep = |).
The 1st column contains the appartment number which if it starts with a 2, such as in 214 means they are located on Floor number 2.
I would like to generate the dates automatically (maybe from the Date command with the week number %V which is starting on mondays) and merge in the names of the tenants from the csv file. Use of the date command and %V is way more complicated than I am used to. I don't know how to tackle this.
Desired Output (sample taken from the 2018 roster):
Week of Floor 1 Floor 2 Floor 3 Floor 4
Sep 18, Nov 27, Feb 5 Ms.X Mr.Y Ms.XX Mr.YY
Sep 25, Dec 4, Feb 19 Ms.AA Ms.BB Mr.CC Mrs.DD
...
So far, I have only this as the displaying (which i can handle i think) depends how i get the date command to give me the proper dates:
roster_start=$(date -d "20190211") # 11 fev 2019 start of cleaning roster
yr=2019; wk=6
date -d "Feb 6 $yr" +%V
date -d "20190211"
printf "\nWeek of\tFloor 1\t\tFloor 2\t\tFloor 3\t\tFloor 4\n"; \
for wk in 6 16 26 "$yr"; do
printf "%s\t" "$d"
date -d "$wk" +"%b %e"
done
Thank you for any help you can provide.

Building Bootstrap 4 with Sass - result not same as dist/bootstrap.css

I'm new to Sass and trying to compile Bootstrap so I can change the md breakpoint such that a menu will display in touch mode on a 7inch tablet.
Before I made any changes, I thought I'd make sure I can compile it OK by doing a diff on my complied version vs the one on the dist directory - however the file I've complied is over 20kb smaller than the one in dist (V4 downloaded today).
I open the files hoping it would be just whitespace and comments, but there are actual differences in the CSS.
My build process is below.
$ sass -v
Sass 3.5.5 (Bleeding Edge)
$ pwd
/Volumes/projects/xx/resp/bootstrap-4.0.0
$ dir
drwxrwxr-x 4 xx staff 16384 12 Feb 2018 dist
...
drwxrwxr-x 4 xx staff 16384 12 Feb 2018 scss
$ sass -f scss/bootstrap.scss dist/css/TESTbootstrap.css
$ dir dist/css
-rwxrw-r-- 1 kevin xx 152719 12 Feb 2018 TESTbootstrap.css
...
-rwxrw-r-- 1 kevin x 178152 18 Jan 10:29 bootstrap.css

Recursively searching a directory without changing directory atimes

I'm checking an alternative to 'find' command in shell scripting so as to eliminate the discrepancy of Accessed date of sub directories.
According to my observation, when find command is executed to list all the files in a directory, the accessed date of sub-directories is getting changed.
I want to post genuine statistics in one of the junk platforms, So I have been looking at some forums and got the alternative with 'ls' command. But that doesn't completely fulfill my request.
Below is the answer given by #ghostdog74.
ls -R %path% | awk '/:$/&&f{s=$0;f=0} /:$/&&!f{sub(/:$/,"");s=$0;f=1;next} NF&&f{ print s"/"$0 }'.
But this finds only the files inside the sub directories. I need all the files and sub-directories' files to be listed.
For example:
bash-3.2# pwd
/Users/manojkapalavai/Desktop/SleepTimeReport
bash-3.2# ls
**6th floor** manoj17 manoj26.txt manoj36 manoj45.txt manoj55 manoj70.txt manoj80 manoj9.txt **test1**
manoj14 manoj23.txt manoj33 manoj42.txt manoj52 manoj61.txt manoj71 manoj80.txt manoj90 **test2**.
The highlighted ones are sub-directories inside "SleepTimeReport" directory and remaining are just files. So, when I execute the above command, I get only the below output.
bash-3.2# ls -R ~/Desktop/SleepTimeReport | awk '/:$/&&f{s=$0;f=0} /:$/&&!f{sub(/:$/,"");s=$0;f=1;next} NF&&f{ print s"/"$0 }'.
~/Desktop/SleepTimeReport/6th floor/Script to increase the Sleep Time.numbers.
~/Desktop/SleepTimeReport/6th floor/Zone1Sleep.pages.
~/Desktop/SleepTimeReport/test1/New_folder.
~/Desktop/SleepTimeReport/test1/manoj.txt.
~/Desktop/SleepTimeReport/test1/sathish.txt.
~/Desktop/SleepTimeReport/test1/vara.txt.
~/Desktop/SleepTimeReport/test1/New_folder/Script to increase the Sleep Time.numbers.
~/Desktop/SleepTimeReport/test1/New_folder/Zone1Sleep.pages.
i.e.; only those files inside sub-directories are listed.
Brief explanation of what issue I'm facing, please see below
Manojs-MacBook-Pro:SleepTimeReport manojkapalavai$ ls -l
total 16
drwxr-xr-x 8 manojkapalavai staff 272 Sep 14 15:07 6th floor
-rwxr-xr-x 1 manojkapalavai staff 59 Nov 13 10:41 AltrFind.sh
-rw-r--r-- 1 manojkapalavai staff 0 Nov 2 15:15 manoj%.txt
-rw-r--r-- 1 manojkapalavai staff 0 Nov 2 18:23 manoj1
When I try finding Created time and Accessed Time of the folder 6th floor before using 'find' command, the below is output.
Manojs-MacBook-Pro:SleepTimeReport manojkapalavai$ stat -f '%N, %SB, %Sa' 6th\ floor/
6th floor/, Sep 13 10:34:55 2017, **Nov 13 11:21:33 2017**
Manojs-MacBook-Pro:SleepTimeReport manojkapalavai$ find /Users/manojkapalavai/Desktop/SleepTimeReport/
/Users/manojkapalavai/Desktop/SleepTimeReport/
/Users/manojkapalavai/Desktop/SleepTimeReport//6th floor
/Users/manojkapalavai/Desktop/SleepTimeReport//6th floor/.DS_Store
/Users/manojkapalavai/Desktop/SleepTimeReport//6th floor/Script to increase the Sleep Time.numbers
/Users/manojkapalavai/Desktop/SleepTimeReport//6th floor/Zone1Sleep.pages
Now, after finding all the files inside a directory, below is the output of atime. you can notice the change
Manojs-MacBook-Pro:SleepTimeReport manojkapalavai$ stat -f '%N, %SB, %Sa' 6th\ floor/
6th floor/, Sep 13 10:34:55 2017, **Nov 13 14:26:03 2017**
All tha I have done is just find the files, and atime of sub-folders inside a folder when we find is getting changed to that current time.
Is there any way to solve this?
ls is the wrong tool for programmatic use. Generally, you should be able to fix your find usage to not have an effect on atimes (actually, it's pretty rare for folks to even have atimes enabled at the filesystem level on modern production systems), but if you really want to avoid it, consider the bash globstar option:
shopt -s globstar
for file in **/*; do
echo "Doing whatever with $file"
done

Display Previous Months in Shell

I have extracted the current month using
currentMonth=`date +"%b"`
I want to get all previous five months in a file. Suppose its October now, i want Sep, Aug, Jul, Jun, May in a file. I tried using multiple utilities like cal, ncal, date but could not achieve this.
I want the months in the file as
Sep
Aug
Jul
Jun
May
Any help or suggestion is greatly appreciated.
Simple bash/shell solution (for Unix):
for i in 1 2 3 4 5; do date -d" - $i month" +%b; done
The output:
Sep
Aug
Jul
Jun
May
For MacOS:
for i in {1..5}; do date -v-"$i"m +%b; done

Use cat to combine mp3 files based on filename

I have a large number of downloaded radio programs that consist of 4 mp3 files each. The files are named like so:
Show Name - Nov 28 2011 - Hour 1.mp3
Show Name - Nov 28 2011 - Hour 2.mp3
Show Name - Nov 28 2011 - Hour 3.mp3
Show Name - Nov 28 2011 - Hour 4.mp3
Show Name - Nov 29 2011 - Hour 1.mp3
Show Name - Nov 29 2011 - Hour 2.mp3
Show Name - Nov 29 2011 - Hour 3.mp3
Show Name - Nov 29 2011 - Hour 4.mp3
Show Name - Nov 30 2011 - Hour 1.mp3 and so on...
I have used the cat command to join the files with great success by moving the four files of the same date into a folder and using the wildcard:
cat *.mp3 > example.mp3
The files are all the same bitrate, sampling rate, etc.
What I would like to do is run a script that will look at the file name and combine hours 1-4 of each date and name the file accordingly. Just the show name, the date and drop the 'Hour 1'.
I looked around and found a number of scripts that can be used to move files around based on their names but I'm not adept enough at bash scripting to be able to understand the methods used and adapt them to my needs.
I'm using Ubuntu 14.04.
Many thanks in advance
You can use a bash for loop to find each distinct date name and then construct the expected mp3 names from that.
Because your files have spaces in their names and my solution uses globbing, you'll also have to edit your Internal Field Separator to ignore spaces for the duration of the script.
SAVEIFS=$IFS
IFS=$'\n\b'
for mdy in `/bin/ls *mp3 | cut -d' ' -f'4,5,6' | sort -u`; do
cat *${mdy}*.mp3 > "showName_${mdy}_full.mp3"
done
IFS=$SAVEIFS
This won't alert you if some hours are missing for some particular date. It'll just join together whatever's there for that date.
Note: The comment pointing out that cat probably won't work for these files is spot on. The resulting file will probably be corrupted. You probably want to use something like mencoder or ffmpeg instead. (Check out this thread.)

Resources