OK, with 20 replicates, the normality assumption might hold, but I'm not fully sure how to test it: the best way to decide is usually by qq plots and the like, that's not feasible for 100 genera. You could use a normality test, but, first, that's not great (failure to reject the null that it's normal doesn't necessarily mean that it's normal), and second you would end up doing different tests for each genera, that doesn't sound great. So I would still err on the side of a Wilcoxon, but I might be wrong.
As for looping, yes, it's doable. You can use a for loop, it would look something like:
p_values <- numeric(length = nrow(input_df))
for(i in seq_len(nrow(input_df)){
p_values[[i]] <- wilcox.test(input_df[i, 1:20], input_df[i, 21:40])$p.val
}
p_adj <- p.adjust(p_values)
(not tested, needs to be adapted to your data, this is just to give a general structure).