How can I deal with Makefile syntax error made by "tab"? - shell

I am not familiar with shell. I just want to successfully run this piece of code which I downloaded from Github. When I directly ran the code with the command,
make file='example.txt' file_test
it didn't work, and here is the error.
makefile line 1: syntax error: unexpected end of file
I tried to fix the problem by unifying the encoding format of 'Makefile.sh' and 'example.txt' to be Unix, but still it did not work at all.
Then I asked my friend(he is also new to shell), and he told me to delete the "tab" before each line(not including the command lines). The error is different at this time, but I still could not fix it by using Google.
Makefile:75: *** commands commence before first target. Stop.
Please, somebody can help? It is driving me crazy and I have no time left for solving this problem. :( Thanks!!!
And, here is the code after I deleted the 'TAB'.
# State-of-the-art paper: http://www.aclweb.org/anthology/P18-1016
########################################Definitions########################################
SHELL := /bin/bash
NC := \033[0m
RED := \033[0;31m
GREEN := \033[0;32m
CYAN := \033[0;36m
work_dir := $(PWD)
script_dir := $(work_dir)/scripts
NTS_dir := $(work_dir)/NeuralTextSimplification_model
file?=""
filetype := $(shell file $(file) | cut -d: -f2)
article_name := $(basename $(notdir $(file)))
article_simple := $(basename $(file))-simple.txt
NTS_script := $(NTS_dir)/src/scripts/translate.sh
NTS_input := $(NTS_dir)/data/test.en
NTS_result_file = $(NTS_dir)/results_NTS/result_NTS_epoch11_10.19.t7_5
# passage = xml file representing a sentence parsed with TUPA
sentence_dir = $(script_dir)/sentences/$(article_name)
passage_dir = $(script_dir)/passages/$(article_name)
sentences = $(sentence_dir)/*.txt
passages = $(passage_dir)/*.xml
############################################################################################
.SILENT:
.ONESHELL: # To execute all commands in one single bash shell
.PHONY: all file_test NTS DSS tupa_parse split_to_sentences help clean
all: file_test $(article_simple)
printf "\n${GREEN}Article simplified :\n====================${NC}\n\n"
cat $(article_simple)
# evaluate the system results using BLUE & SARI metrics
# The original test.en must be given to evaluate (https://github.com/senisioi/NeuralTextSimplification)
evaluate: all
printf "\n${GREEN}Evaluating: (the original test.en must be given)${NC}\n\n"
python $(NTS_dir)/src/evaluate.py $(NTS_input) $(NTS_dir)/data/references/references.tsv $(NTS_dir)/predictions
############################################################################################
# The following targets are only useful as aliases for testing
# Generates the corresponding NTS model result file.
NTS: file_test $(NTS_result_file)
# Generates the article sentences split using the two semantic rules mentioned in the paper.
DSS: file_test $(NTS_input)
# Parses the article's sentences using TUPA -> output : xml files
tupa_parse: file_test $(passages)
# Splits the article into sentences, each one in a single file
split_to_sentences: file_test $(sentences)
#############################################################################################
# Testing the validity of the file
file_test:
# Whether the file was provided as an argument
if [ $(file) = "" ]; then
printf "${RED}ERROR${NC}: One & only file must be given in argument! Please specify it by:\nmake file=<file_name> <target>\n\n"; exit 1
fi
# Whether the file exists
if [ ! -f $(file) ]; then
printf "$(RED)ERROR${NC}: $(file) File not found!\n\n"; exit 1
fi
# Whether the file is empty
if [ ! -s $(file) ]; then
printf "$(RED)ERROR${NC}: $(file) is empty!\n\n"; exit 1
fi
# Whether it is a text file
if [[ ! "$(filetype)" = *"ASCII"* && ! "$(filetype)" = *"UTF-8"* ]]; then
printf "$(RED)ERROR${NC}: Only text files (ASCII or UTF-8 Unicode text) are accepted!\n\n"; exit 1
fi
# Prints help on the useful targets for the user
help:
printf "\n${CYAN}make file=<file_path>${NC} : Executes the simplification completely and avoids rebuilding if unnecessary.\n\n"
printf "${CYAN}make file=<file_path> file_test${NC} : Tests whether the given file is valid.\n\n"
printf "${CYAN}make file=<file_path> NTS${NC} : Generates the corresponding NTS model result file.\n\n"
printf "${CYAN}make file=<file_path> DSS${NC} : Generates the article's sentences split using the two semantic rules mentioned in the paper.\n\n"
printf "${CYAN}make file=<file_path> tupa_parse${NC} : Parses the article's sentences using TUPA -> output : xml files.\n\n"
printf "${CYAN}make file=<file_path> split_to_sentences${NC} : Splits the article into sentences, each one in a single file.\n\n"
printf "${CYAN}make clean${NC} : Cleans results of previous executions.\n\n"
##############################################################################################
# Produces the simple version of text as an output and writes it to "article_simple" variable
$(article_simple): $(NTS_result_file)
cd $(work_dir)
cat $(NTS_result_file) > $(article_simple)
# Equivalent for target NTS
$(NTS_result_file): $(NTS_script) $(NTS_input)
printf "\n${GREEN}Simplifying sentences using the NTS model : ... ${NC}\n\n"
cd $(NTS_dir)/src/scripts/
source ./translate.sh
# Equivalent for target DSS
$(NTS_input): $(script_dir)/split_sentences.py $(passages)
printf "\n${GREEN}Splitting the article's sentences : ... ${NC}\n"
python $(script_dir)/split_sentences.py $(passage_dir) > $(NTS_input)
# If the output of the splitting is empty, then it failed
if [ ! -s $(NTS_input) ]; then
printf "$(RED)ERROR${NC}: Splitting failed!\n\n"; exit 1
fi
# Equivalent for target tupa_parse
$(passages): $(sentences) | $(passage_dir)
printf "\n${GREEN}Parsing the article's sentences : ... ${NC}\n\n"
python -m tupa $(sentences) -m $(work_dir)/TUPA_models/ucca-bilstm
mv *.xml $(passage_dir)
# Equivalent for target split_to_sentences
$(sentences): $(file) $(script_dir)/article_to_sentences.py | $(sentence_dir)
python $(script_dir)/article_to_sentences.py $(file)
# Creates the passage directory
$(passage_dir): $(file)
if [ -d $(passage_dir) ]; then
rm -f $(passage_dir)/*.xml
else
mkdir -p $(script_dir)/passages/
mkdir $(passage_dir)/
fi
# Creates the sentence directory
$(sentence_dir): $(file)
if [ -d $(sentence_dir) ]; then
rm -f $(sentence_dir)/*.txt
else
mkdir -p $(script_dir)/sentences/
mkdir $(sentence_dir)
fi
# Cleans the residues from previous executions
clean:
rm -rf $(passage_dir)* $(sentence_dir)*
echo > $(NTS_result_file)

Related

Makefile ifeq always true

I have the following Makefile target:
target1:
$(eval count_abc := $(shell grep -c "ABC" myFileA))
$(eval count_def := $(shell grep -c "DEF" myFileB))
echo $(count_abc)
echo $(count_def)
ifeq ($(count_abc),$(count_def))
echo "TRUE"
else
echo "FALSE"
endif
But the output is always TRUE, e.g.:
echo 22
22
echo 21
21
echo TRUE
TRUE
What am I doing wrong here? What I want is INSIDE the target do 2 greps and compare their outputs and do something or something else based on the result. Please note that the greps must be done within the target since myFileA and myFileB get created on the target before and don't exist at the beginning when running make.
Thanks,
Amir
The rule file for "make" is declarative in nature - the makefile defines rules and targets, and then the make program evaluate the rules, and decide which action to take based on the target. As a result, execution is not always in the order the lines are entered into the file.
More specifically, the "ifeq" is evaluated at the rule definition stage, but the actions for building the target (eval count_abc ...) are executed when the target is built. As a result, when the ifeq is processed, both count_abc and count_def are still uninitialized, expanded to empty strings.
For the specific case you described - building a target that will compare the grep -c output from the two files, you can try something like below, effectively using shell variables (evaluated when target is evaluated), and not make variables (which are mostly declarative, evaluated when makefile is read)
target1:
count_abc=$(grep -c "ABC" myFileA) ; \
count_def=$(grep -c "DEF" myFileB) ; \
echo $(count_abc) ; \
echo $(count_def) ; \
if [ "$count_abc" -eq "$count_def" ] ; then echo TRUE ; else echo FALSE ; fi
Disclaimer: I did not run the revised makefile, not having access to desktop at this time.

Recursively create directories for all letters

I would like to create a folder structure based on a brace expansion such as {a-z}. Each string generated by the brace-expansion should be a new folder. Furthermore, each of these folders should contain the same set of subfolders similarly generated. And this up to a given level.
An example for the range a-z and depth 16
a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/
a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/b/
a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/c/
...
d/a/h/r/y/d/s/b/e/y/k/f/o/o/q/c/
...
z/z/z/z/z/z/z/z/z/z/z/z/z/z/z/y/
z/z/z/z/z/z/z/z/z/z/z/z/z/z/z/z/
The following code allows me to go upto depth 2:
for x in {a..z} ; do mkdir -p $x/{a..z} ; done
But how do I go further?
A recursive solution. Job is called with 2 params: max_depth and base_path
#!/bin/bash
function job()
{
local depth=$(($1-1))
local path=$2
local x
for x in a b c # reduced for test
do
mkdir -p "$path/$x"
((depth>0)) && job $depth "$path/$x"
done
}
job 3 ./test
Proof it with:
find test -type d
The simplest form would be to use any of the following lines:
mkdir -p {a..c}/{a..c} # depth 2
mkdir -p {a..c}/{a..c}/{a..c} # depth 3
mkdir -p {a..c}/{a..c}/{a..c}/{a..c} # depth 4
...
The brace-expansion will make all combinations and mkdir -p will take care of the rest.
Of course, you do not want to type this over and over for various sets. So you could generate the full brace-expansion-string with bash and use exec to process the brace-expansion-string before passing it to mkdir -p:
depth=3
set={a..c}
dirs=$(printf "/${set}%.0s" $(seq $depth))
mkdir -p $(eval echo .${dirs})
Be aware however that if your set has length m, and you want a depth of n, you are creating m^n directories. This number could conflict with the number of arguments you can pass on to a program.
Related information:
What is the maximum allowed depth of sub-folders?
https://www.in-ulm.de/~mascheck/various/argmax/
A recursive funcion may solve your problem. Take care with inodes generation when using high directory levels...
#!/bin/bash
function createDir {
mkdir -p $1 && cd $1;
for x in {a..z} ; do
local i=$(($2-1))
[ $i -lt 0 ] && continue;
createDir $x $i
done
cd ..
}
createDir $1 $2
Save into a file, like mkdir.sh, and call it: ./mkdir.sh <main_folder> <level>.

batch processing : File name comparison error

I have written a program (Cifti_subject_fmri) which compares whether file name matches in two folders and essentially executes a set of instructions
#!/bin/bash -- fix_mni_paths
source activate ciftify_v1.0.0
export SUBJECTS_DIR=/scratch/m/mchakrav/dev/functional_data
export HCP_DATA=/scratch/m/mchakrav/dev/tCDS_ciftify
## make the $SUBJECTS_DIR if it does not already exist
mkdir -p ${HCP_DATA}
SUBJECTS=`cd $SUBJECTS_DIR; ls -1d *` ## list of my subjects
HCP=`cd $HCP_DATA; ls -1d *` ## List of HCP Subjects
cd $HCP_DATA
## submit the files to the queue
for i in $SUBJECTS;do
for j in $HCP ; do
if [[ $i == $j ]];then
parallel "echo ciftify_subject_fmri $i/filtered_func_data.nii.gz $j fMRI " ::: $SUBJECTS |qbatch --walltime '05:00:00' --ppj 8 -c 4 -j 4 -N ciftify_subject_fmri -
fi
done
done
When i run this code in the cluster i am getting an error which says
./Cifti_subject_fmri: [[AS1: command not found
The query ciftify_subject_fmri is part of toolbox ciftify, for it to execute it requires following instructions
ciftify_subject_fmri <func.nii.gz> <Subject> <NameOffMRI>
I have 33 subjects [AS1 -AS33] each with its own func.nii.gz files located SUBJECTS directory,the results need to be populated in HCP directory, fMRI is name of file format .
Could some one kindly let me know why i am getting an error in loop

accessing newly created directory in shell script

I'm attempting to make a new folder, a duplicate of the input, and then tar the contents of that folder. I can't figure out why - but it seems like instead of searching the contents of my newly created directory - it is searching my entire computer... returning lines such as
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Sine/Sine - Vocal 1.raw is a file
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Sine/Sine - Vocal 2.raw is a file
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Sine/Triangle - Arp.raw is a file
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Sine/Triangle - Asym 4.raw is a file
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Sine/Triangle - Eml.raw is a file
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Square is a folder
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Square/Square - Arp.raw is a file
/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Resources/Libraries/WaveOsc/Square/Square - Bl Saw.raw is a file
can you guys spot a simple error?
BTW, I know that the script to tar isn't present yet, but that will be easy once i can navigate the new folder.
#!/bin/bash
##--- deal with help args ------------------
##
print_help_message() {
printf "Usage: \n"
printf "\t./`basename $0` <input_dir> <output_dir>\n"
printf "where\n"
printf "\tinput_dir : (required) the input directory.\n"
printf "\toutput_dir : (required) the output directory.\n"
}
if [ "$1" == "help" ]; then
print_help_message
exit 1
fi
## ------ get cli args ----------------------
##
if [ $# == 2 ]; then
INPUT_DIR="$1"
OUTPUT_DIR="$2"
fi
## ------ tree traversal function -----------
##
mkdir "$2"
cp -r "$1"/* "$2"/
## ------ return output dir name ------------
##
return_output_dir() {
echo $OUTPUT_DIR/$(basename $(basename $(dirname $1)))
}
bt() {
output_dir="$1"
for filename in $output_dir/*; do
if [ -d "${filename}" ]; then
echo "$filename is a folder"
bt $filename
else
echo "$filename is a file"
fi
done
}
## ------ main ------------------------------
##
main() {
bt $return_output_dir
exit 0
}
main
}
Well, I can tell you why it's doing that, but I'm not clear on what it's supposed to be doing, so I'm not sure how to fix it. The immediate problem is that return_output_dir is a function, not a variable, so in the command bt $return_output_dir the $return_output_dir part expands to ... nothing, and bt gets run with no argument. That means that inside bt, output_dir gets set to the empty string, so for filename in $output_dir/* becomes for filename in /*, which iterates over the top-level items on your boot volume.
There are a number of other things that're confusing/weird about this code:
The function main() doesn't seem to serve any purpose -- some of the main-line code is outside it (notably, the argument parsing stuff), some inside, for no apparent reason. Having a main function is required in some languages, but in a shell script it generally makes more sense to just put the main code inline. (Also, functions shouldn't exit, they should return.)
You have variables named both OUTPUT_DIR and output_dir. Use distinct names. Also, it's generally best to stick to lowercase (or mixed-case) variable names, to avoid conflicts with the variables that're used by the shell and other programs.
You copy $1 and $2 into INPUT_DIR and OUTPUT_DIR, then continue to use $1 and $2 rather than the more-clearly-named variables you just copied them into.
output_dir is changed in the recursive function, but not declared as local; this means that inner invocations of bt will be changing the values that outer ones might try to use, leading to weirdness. Declare function-local variables as local to avoid trouble.
$(basename $(basename $(dirname $1))) doesn't make sense. Suppose $1 is "/foo/bar/baz/quux": then dirname $1 returns /foo/bar/baz, basename /foo/bar/baz returns "baz", and basename baz returns "baz" again. The second basename isn't doing anything! And in any case, I'm pretty sure the whole thing isn't doing what you expect it to.
What directory is bt supposed to be recursing through? Nothing in how you call it has any reference to either INPUT_DIR or OUTPUT_DIR.
As a rule, you should put variable references in double-quotes (e.g. for filename in "$output_dir"/* and bt "$filename"). You do this in some places, but not others.

GNU override target?

I'm wondering if it's possible to override a target in a makefile! The environment I'm working in does not allow me to do this due to auto generation! I was wondering if I coded the same rule above or below the static target would this achieve an override?
%_emul.flist: $(if ${GEN_FLIST},%_synth.flist,) ${rdlh_file_deps}
${QUIET}if test ${SYN_DEBUG} -eq 1 ; then set -xv ; fi; \
$(if ${TOOL_VERILOG},rm -f $#; touch $#,$(if ${TOOL_BBOX_LIBS},echo ${TOOL_BBOX_LIBS} > $#,rm -f $#; touch $#))
/bin/sed -e '/\/libs\//d' -e '/\/place\//d' $(foreach mod,$(filter %.vhd,$^),-e 's%^\(.*\/\)\{0,1\}$(basename $(notdir ${mod}))\.v$$%${mod}%') $*_synth.flist >> $#
Yes , i think that would work .... but you need to be a bit more careful in the way you code things. You don't want to override something that might be useful!
GNU make would take the most recent of the target it encounters. So, the following works (but not as i would have liked it to work :( )
Output: I think you are looking for something like this --
Kaizen ~/make_prac $ make -nf mk.name
mk.name:20: warning: overriding recipe for target `name'
mk.name:17: warning: ignoring old recipe for target `name'
arg1="Kaizen" ;
echo "hello "" ;" ;
hello ;
Code: Here the target "name" appears twice and is overridden.
Kaizen ~/make_prac $ cat mk.name
##
## make to accept name and display hello name
##
arg1="" ;
.PHONY : name \
hello
#.DEFAULT :
# hello
hello : name
+ echo "hello $(arg1)" ;
name :
echo "name given is : $(arg1)" ;
name :
arg1="Kaizen" ;
PS: Take note of the use of : -- if you use :: then both rules get executed.
Explanation for the arg1 .... not showing in the output: The variable arg1, even though it gets assigned in the first parsing, it gets ignored, since its assignment is target dependent. If you would have had a variable declaration elsewhere -- e.g. like arg1 is defined at the start -- there would not be any dereferencing issues.

Resources