How to use make to keep a file synced? - file

If doing:
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
GITIGNORE_SOURCE_PATH := ../.gitignore
GITIGNORE_DESTINE_PATH := ./setup/.gitignore
start_syncing: "${GITIGNORE_DESTINE_PATH}"
printf '\n'
"${GITIGNORE_DESTINE_PATH}":
cp -vr "${GITIGNORE_SOURCE_PATH}" ./setup/
Make keeps running the rule "${GITIGNORE_DESTINE_PATH}" every time when I call make, but it should only call it when the source file ../.gitignore is modified.
Update 3
This is the make file I was suggested to use on comment:
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
GITIGNORE_SOURCE_PATH := ../.gitignore
GITIGNORE_DESTINE_PATH := ./setup/.gitignore
start_syncing: "${GITIGNORE_DESTINE_PATH}"
printf '\n'
${GITIGNORE_DESTINE_PATH}: ${GITIGNORE_SOURCE_PATH}
cp -vr "${GITIGNORE_SOURCE_PATH}" ./setup/
Running it, it says:
$ ls -l ../.gitignore
-rwx---r-x+ 1 User None 488 Apr 27 23:23 ../.gitignore
$ ls -l ./setup/.gitignore
-rwx---r-x+ 1 User None 488 Apr 28 07:41 ./setup/.gitignore
$ make
make: *** No rule to make target '"./setup/.gitignore"', needed by 'start_syncing'. Stop.

The solution is to remove double quotes from the target rules. In case they have a space on the name, there is nothing make can do about it other than you manually escape the values of the space with \
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
GITIGNORE_SOURCE_PATH := ../.gitignore
GITIGNORE_DESTINE_PATH := ./setup/.gitignore
start_syncing: ${GITIGNORE_DESTINE_PATH}
printf '\n'
${GITIGNORE_DESTINE_PATH}: ${GITIGNORE_SOURCE_PATH}
cp -vr "${GITIGNORE_SOURCE_PATH}" ./setup/

Related

How to store variables from loop to a file

I am trying to store the variables $d, $tf_name, $db_orig created in the following loop to a file.I want to end up with a tab separated MY_FILE.txt containing the following fields $d, $tf_name, $db_orig and each iteration of this set of variables to be stored in a new line in the file MY_FILE.txt.
MY_ARRAY=()
for d in */
do
IN=$d
folderIN=(${IN//_/ })
tf_name=${folderIN[-1]%/*}
db_orig=${folderIN[-2]%/*};
ENTRY="$d\t$tf\t$id\t$db_orig\n"
MY_ARRAY+=$ENTRY
done
$MY_ARRAY > MY_FILE.txt
It doesn't recognise \t and \n as TAB and NEWLINE respectively. It stores all the values next to each other in the same line without TAB, in the array MY_ARRAY.
Any help?
Yes, this happens because $MY_ARRAY > MY_FILE.txt is not a valid command.
You need to print your array to the file.
And in order to print it correctly you need either to use
echo -e "${MY_ARRAY[#]}" >file or printf
By man echo
echo -e : enable interpretation of backslash escapes
Moreover, if you need to store the $ENTRY to your array you need to do it like this:
MY_ARRAY+=("$ENTRY")
In any case, you can do it without the need of an array. You can just apply += in the ENTRY : ENTRY+="$d\t$tf\t$id\t$db_orig\n"
Test:
$ e+="a\tb\tc\td\n"
$ e+="aa\tbb\tcc\tdd\n"
$ e+="aaa\tbbb\tccc\tddd\n"
$ echo -e "$e"
a b c d
aa bb cc dd
aaa bbb ccc ddd
# Test with array
$ e="a\tb\tc\td\n" && myar+=("$e")
$ e="aa\tbb\tcc\tdd\n" && myar+=("$e")
$ e="aaa\tbbb\tccc\tddd\n" && myar+=("$e")
$ echo -e "${myar[#]}"
a b c d
aa bb cc dd
aaa bbb ccc ddd
#Alternative array printing
$ for i in "${myar[#]}";do echo -en "$i";done
a b c d
aa bb cc dd

makefile missing separator in Mac OS X

I have a makefile which gives the following error in OS X, I will be very grateful if someone have an idea about why is getting this error:
./../../../..//Source//templates/gcc/Makefile.posix:15: *** missing separator. Stop.
Here is the makefile:
GNU_INSTALL_ROOT := /usr/local/gcc-arm-none-eabi-4_8-2014q3
GNU_VERSION := 4.8.3
GNU_PREFIX := arm-none-eabi
GDB_PORT_NUMBER := 9992
FLASH_START_ADDR = $(shell $(OBJDUMP) -h $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out -j .text | grep .text | awk '{print $$4}')
JLINK_OPTS = -device nrf51822 -if swd -speed 4000
JLINK_GDB_OPTS = -noir
JLINK = JLinkExe $(JLINK_OPTS)
JLINKD_GDB = JLinkGDBServer $(JLINK_GDB_OPTS)
flash-jlink: flash.jlink
$(JLINK) flash.jlink
flash.jlink:
printf "loadbin $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin $(FLASH_START_ADDR)\nr\ng\nexit\n" > flash.jlink
erase-all: erase-all.jlink
$(JLINK) erase-all.jlink
erase-all.jlink:
# Write to NVMC to enable erase, do erase all, wait for completion. reset
printf "w4 4001e504 2\nw4 4001e50c 1\nsleep 100\nr\nexit\n" > erase-all.jlink
run-debug:
$(JLINKD_GDB) $(JLINK_OPTS) $(JLINK_GDB_OPTS) -port $(GDB_PORT_NUMBER)
.PHONY: flash-jlink flash.jlink erase-all erase-all.jlink run-debug
TAB character in Brackets editor were replaced by 4 spaces (sp sp sp sp). Changing to other editor (TextMate) solved the problem
I was using VIM (on MacOS) and found that 'expandtab' was the issue when parsing Makefiles. If set, it turns your tab into 4 spaces. (so i commented it out)
" expand tabs into spaces
"set expandtab
On Mac OS X and SublimeText 3 I had to change the indentation from spaces to tabs to solve the same problem '"Makefile:4: *** missing separator. Stop."'.
So I did the following on SublimeText 3 in the lower left corner to fix the error:
Click on Spaces:4 > Tab Width: 4
Click on Spaces: 4 > Convert Indentation to Tab

removing all files except a group in bash

I want to remove all files, but the one that I have in a list. Let's say for the sake of argument that these files are in a array. The array only contains the last three digits of the file, without the extension. all files are extension jpg. This is what I've been trying to do. Files name are in the form of GEDC1227.JPG
pics=(227 222 231 248 252 253 255 272 274 278)
for line in *; do
for j in $pics[#]; do
[[ ${line:5:3} == $j ]] && break
done
rm $line
done
I'm aware that there are easier ways to accomplish this; however, I'm kind of intrigue, why my algorithm is not working. I think is because is getting to the rm $line every time, and I haven't found a way to bypass that line when test condition is true (which is for files that I don't want remove)
You need to continue twice i.e. resume the next iteration of the outer loop:
pics=(227 222 231 248 252 253 255 272 274 278)
for line in *; do
for j in "${pics[#]}"; do
[[ ${line:5:3} == "$j" ]] && continue 2
done
rm -- "$line"
done
Adding quotes to ${pics[#]}. Not really necessary but it's a good practice to prevent word splitting when elements expand.
Quoted second argument to == to prevent interpreting it as a glob pattern.
Added -- to rm to prevent trying to read files starting with - as option and cause an error to rm.
This alternative solution may also apply but needs testing:
shopt -s extglob
shopt -s nullglob
echo rm -- ?????!(227|222|231|248|252|253|255|272|274|278)*
Remove echo if found correct.
continue from bash manual:
continue: continue [n]
Resume for, while, or until loops.
Resumes the next iteration of the enclosing FOR, WHILE or UNTIL loop.
If N is specified, resumes the Nth enclosing loop.
I would also consider doing this without a loop at all.
Something like this can be made to run in parallel and won't choke (like a glob might) if there are many files in the directory.
pics=( 227 222 231 248 252 253 255 272 274 278 )
# convert the array to a regex that matches GEDC.227\.JPG$|GEDC.222\.JPG$|...
keep="$( echo "GEDC.${pics[#]}\\.JPG$" | sed -e 's: :\\.JPG$|GEDC.:g' )"
find -type f -iname GEDC*.jpg \
| egrep -v "$keep" \
| xargs rm

String matching between files Linux

I have two files that I want to compare. The first is tab separated, the second is comma separated and both begin with an ID. I want to match those IDs and do two things. First, I want to print out all of the ones that match between the two files. Then (if possible) I want to print to a separate file all of those that do not match.
The files look like this:
(comma separated)
S-3DFSG,0,254654,3,e /// x, /// 5
S-8FGDG,6,464782,6,i /// n /// n /// e /// n, /// /
S-4SKDH,0,445676,3,n /// e /// p, /// /// F
(tab separated)
S-3DGSF DG 2 5 7 DF 2 2 4684648654
S-4GXBG DF 6 2 4 FD 7 1 2415244459
S-3DFST GA 0 8 4 CF 9 8 2
I tried
grep -F -wf file1 file2 > incommon.txt
For grep fixed pattern -only words that match from these files
But I got nothing output...
Does anyone have any suggestions on how I can improve this? I did think about regex but I am not terribly proficient in its use. I wouldn't mind using it though.
analyze.py:
import re
f = open('tab.txt', 'r')
data_tab = f.read()
f.close()
f = open('csv.txt', 'r')
data_csv = f.read()
f.close()
matches_tab = re.findall(r'^([^\t]+)', data_tab, re.M)
matches_csv = re.findall(r'^([^,]+)', data_csv, re.M)
common = set(matches_tab) & set(matches_csv)
not_common = set(matches_tab) ^ set(matches_csv)
f = open('common.txt', 'w')
for el in common:
f.write(el)
f.write('\n')
f.close()
f = open('not_common.txt', 'w')
for el in not_common:
f.write(el)
f.write('\n')
f.close()
Save this in a file called analyze.py and run the script by using:
python analyze.py
Change tab.txt to your tabbed filename, csv.txt to your comma separated filename, and your lists should be dumped in the working directory.
Let me know if you have any problems.
If you still want to do it in the shell, for the "in common" you may use:
sed 's/\([^,]*\),.*/\1/' commed.txt > __ids.txt
grep -F -f __ids.txt $f tabbed.txt
rm -f __ids.txt
and for the "not in common":
sed 's/\([^,]*\),.*/\1/' commed.txt > __ids.txt
grep -F -v -f __ids.txt $f tabbed.txt
sed 's/\([^\t]*\)\t.*/\1/' commed.txt > __ids.txt
grep -F -v -f __ids.txt $f tabbed.txt
rm -f __ids.txt
Where "commed.txt" is the file comma-separated and "tabbed.txt" is the file tab-separated.
This might fail if the ID may occur elsewhere in the second file! A more robust solution with "grep" is possible if the ID cannot be mistaken for a regexp (no ., ,, \, *, etc).

Bash, confusing results for different file tests (test -f)

I am confused in bash by this expression:
$ var="" # empty var
$ test -f $var; echo $? # test if such file exists
0 # and this file exists, amazing!
$ test -f ""; echo $? # let's try doing it without var
1 # and all ok
I can't understand such bash behaviour, maybe anybody can explain?
It's because the empty expansion of $var is removed before test sees it. You are actually running test -f and thus there's only one arg to test, namely -f. According to POSIX, a single arg like -f is true because it is not empty.
From POSIX test(1) specification:
1 argument:
Exit true (0) if `$1` is not null; otherwise, exit false.
There's never a test for a file with an empty file name. Now with an explicit test -f "" there are two args and -f is recognized as the operator for "test existence of path argument".
When var is empty, $var will behave differently when if quoted or not.
test -f $var # <=> test -f ==> $? is 0
test -f "$var" # <=> test -f "" ==> $? is 1
So this example tells us: we should quote the $var.

Resources