Problem in using shell for loop inside gnu make? - gnu-make

consider the below make file
all:
#for x in y z; \
do \
for a in b c; \
do \
echo $$x$$a >> log_$$x; \
done; \
done
While executing this make file, two file got created log_y and log_z. log_y is having data "yb" and "yc". similarly log_z is having data"zb" and "zc".
Actually I want to create four files(log_y_b, log_y_c, log_z_b, log_z_c). For this i have modified the above make file as,
all:
#for x in y z; \
do \
for a in b c; \
do \
echo $$x$$a >> log_$$x_$$a; \
done; \
done
But its creating only one file log_. What should i have to do to create four files.

Perhaps put braces around the variable names: it works on my system.
all:
#for x in y z; \
do \
for a in b c; \
do \
echo $$x$$a >> log_$${x}_$${a}; \
done; \
done
You can also use foreach:
all:
#$(foreach x,y z,$(foreach a,b c,echo $(x)$(a) >> log_$(x)_$(a);))

log_$$x_$$a in the Makefile turns into log_$x_$a for the shell which is equivalent to log_${x_}${a}. The variable $x_ is undefined, however, so the shell substitutes it by the empty string.
Solution: Properly write the $x variable with curly braces around the name (${variablename}), i.e. for consistency's sake write log_${x}_${a} (or in Makefile style: log_$${x}_$${a}).

Related

For loop variable is empty in gmake

I have a list of header files created thus:
expand=$(1)/$(1).h
HDRS=$(foreach x, $(DIRS), $(call expand,$(x)))
Which yields a list like a/a.h b/b.h ...
but when I use this in a for loop:
for i in $(HDRS) ; do \
echo $$i \
cp $$i $(some_dir) \
done
$$i is empty. And the cp fails, having only one argument.
The usual variants of $$i ( $i, $$i, $(i), ${i} ), don't change anything, nor do the usual variants of $(HDRS) ("$(HDRS)", etc.).
gmake echos the for-loop as
for i in a.h b.h ; \
do \
echo $i \
cp $i somedir \
done
Which looks correct.
But the implicit bash shell emits an error "/bin/sh -c: line 5: syntax error: unexpected end of file"
gmake then exits due to the failed command.
Due to the \, make emits the recipe as a single line. This confuses the shell. Try this instead, using ; in place of the line terminator:
for i in a.h b.h ; \
do \
echo $i ; \
cp $i somedir ; \
done

Calling export in foreach loop

I am tying to pass variables to sub makefiles via export
The main Makefile contains a list of components COMPONENT_LIST that will be compiled. In the rule of the target all I exported the USE_COMP_1, USE_COMP_2and USE_COMP_3 variables using foreach function:
COMPONENT_LIST:=\
COMP_1\
COMP_2\
COMP_3
all:
$(foreach comp,$(COMPONENT_LIST),export USE_$(comp)=y;)
#for comp in $(COMPONENT_LIST) ; do \
make -C $$comp all; \
if [ ! $$? -eq 0 ]; then \
echo "component \"$$comp\" not found. Please make sure that folder \"$$comp\" exist";\
exit 1; \
fi \
done
But in the sub Makefile The value of USE_COMP_1, USE_COMP_2and USE_COMP_3 is empty.
Is there any explanation to this ?
I have found the solution.
every sub-command is run in its own shell
So I missed the the \
all:
$(foreach comp,$(COMPONENT_LIST),export USE_$(comp)=y;)\
for comp in $(COMPONENT_LIST) ; do \
make -C $$comp all; \
if [ ! $$? -eq 0 ]; then \
echo "component \"$$comp\" not found. Please make sure that folder \"$$comp\" exist";\
exit 1; \
fi \
done
In this case the export and the following for loop are run in the same shell

ZSH Completion based on previous flag

I am trying to create a completion where one of my completions will be dynamically generated depending on the values of the other flags. For example
local state
_arguments \
'-f[fabric]:fabric:->fabrics' \
'-c[containers/application where log resides]:container:->containers' \
'-l[name of log file]:log:->logs'
case "$state" in
(fabrics)
_values 'fabrics' \
'fab1' \
'fab2'
;;
(containers)
_values 'containers' \
'container1' \
'container2'
;;
(logs)
# show A B C if "-c container1" was entered
# show D E F if "-c container2" was entered
# show G if "-c" was not provided yet
esac
I am having trouble getting the "-l" flag to be dynamically generated.
We could inspect the $words:
Completion Special Parameters
...
Inside completion widgets, and any functions called from them, some parameters have special meaning;
...
words
This array contains the words present on the command line currently being edited.
-- zshcompwid(1): Completion Special Parameters, Completion Widgets
We could do the stuff like this:
(logs)
local -i index=${words[(I)-c]}
local -i ret=0
if ((index == 0)); then
_values 'logs' F
ret=$?
elif [[ "$words[index+1]" == container1 ]]; then
_values 'logs' A B C
ret=$?
elif [[ "$words[index+1]" == container2 ]]; then
_values 'logs' D E F
ret=$?
fi
return ret
To inspect arrays, it is usefull to use the array Subscript Flags:
Subscript Flags
If the opening bracket, or the comma in a range, in any subscript expression is directly followed by an opening parenthesis, the string up to the matching closing one is considered to be a list of flags, as in name[(flags)exp].
-- zshparam(1), Subscript Flags, Array Subscripts, Array Parameters
So,$words[(I)-c] means I "flag" + -c as "exp" for $words which is "Last matching element's index for "-c" in the array $word". For example:
$ tmp=(my-test-command -f flag -c container1 -l)
$ echo $tmp[(I)-c]
4
$ echo $tmp[(I)container1]
5
$ tmp=(my-test-command -f flag -c container1 -c container2 -l)
$ echo $tmp[(I)-c]
6

How to run Ag asynchronously with vimproc and quickrun - VIM?

I'm using Ag, vimproc, quickrun
I'm able to run .php asynchronously with this settings in my .vimrc
nnoremap <leader>r :QuickRun<CR>
let g:quickrun_config = get(g:, 'quickrun_config', {})
let g:quickrun_config = {
\ "_" : {
\ 'runner': 'vimproc',
\ 'runner/vimproc/updatetime': 60,
\ 'outputter/quickfix': ':quickrun-module-outputter/quickfix',
\ 'outputter/buffer/split': ':rightbelow 8sp',
\ },
\}
Does anyone know how can I run ag asynchronously?
Ag settings in .vimrc
if executable("ag")
let g:ctrlp_user_command = 'ag %s -i --nocolor --nogroup --hidden
\ --ignore .git
\ --ignore .svn
\ --ignore .hg
\ --ignore .DS_Store
\ --ignore "**/*.pyc"
\ -g ""'
endif
nnoremap <leader>a :Ag!<Space>
nnoremap <leader>aa :Ag! <C-r>=expand('<cword>')<CR>
nnoremap <leader>aaa :Ag! <C-r>=expand('<cword>')<CR><CR>
A generic solution to use asynchronous command with Vim is using a plugin called vim-dispatch, you can launch command in the background with :Start!
Alternatively, this is also a fork of vim called neovim, which is trying to address that issue. At the time of this post, it is not necessarily mature enough, but this is something to consider as well for the future.

Cshell and Awk Infinite Running

When I run the below program, I get no return, however the program still runs forever until I end it. Can some one please exoplain to me why this would happen. I am trying to get this complex awk statement to work, however, have been very unsuccessful.
The code I am using for my Cshell is (its all on one line, but I split it here to make it easier to read):
awk '{split($2,b,""); counter = 1; while (counter < 13)
{if (b[counter] == 1 && "'$cmonth'" > counter)
{{printf("%s%s%s\n", $1, "'$letter'","'$year3'")}; counter++;
else if (b[counter] == 1 && "'$cmonth'" <= counter)
{{printf("%s%s%s\n", $1, "'$letter'","'$year2'")}; counter++;}
else echo "fail"}}' fileRead >> $year$month
The text file I am reading from looks like
fff 101010101010
yyy 100100100100
Here $year2 and $year3 represent counters that start from 1987 and go up 1 year for each line read.
$cmonth is just a month counter from 1–12.
$letter is just a ID.
The goal is for the program to read each line and print out the ID, month, and year if the position in the byte code is 1.
You have some mismatched curly braces, I have reformatted to one standard of indentation.
awk '{ \
split($2,b,""); counter = 1 \
while (counter < 13) { \
if (b[counter] == 1 && "'$cmonth'" > counter){ \
printf("%s%s%s\n", $1, "'$letter'","'$year3'") \
counter++ \
} \
else if (b[counter] == 1 && "'$cmonth'" <= counter) { \
printf("%s%s%s\n", $1, "'$letter'","'$year2'") \
counter++ \
} \
else print "fail" \
} # while \
}' fileRead >> $year$month
Also awk does'nt support echo.
Make sure that the \ is the LAST char on the line (no space or tab chars!!!), or you'll get a syntax error.
Else, you can 'fold' up all of the lines into one line. adding the occasional ';' as needed.
edit
OR you can take the previous version of this awk script (without the \ line continuation chars), put it in a file (without any of the elements outside of the ' ....' (single quotes) and call it from awk as a file. You'll also need to made so you can pass the variables cmonth, letter, year2 and any others that I've missed.
save as file
edit file, remove any `\' chars, change all vars like "'$letter'" to letter **
call program like
**
awk -v letter="$letter" -v year2="$year2" -v month="$month" -f myScript fileRead >> $year$month
**
for example
printf("%s%s%s\n", $1, "'$letter'","'$year2'")
becomes
printf("%s%s%s\n", $1, letter,year2)
IHTH.

Resources