2

I've got the following shell script

#!/bin/bash

Search elixir code with ack

By default skip the dependencies and test directories

ignore_dirs=("dependencies" "test" "config")

the for call below inserts newlines so we need to strip them out which is why the tr -d part is on the end

of the assignment

ign_dirs="$(for i in "${ignore_dirs[@]}"; do echo "--ignore-dir=$i "; done | tr -d '\n')"

By default skip the mix.exs file

ignore_files=("is:mix.exs" "is:credo.exs") ign_files="$(for i in "${ignore_files[@]}"; do echo "--ignore-file=$i "; done | tr -d '\n')"

pager=less file_types=elixir:ext:ex,exs,eex,heex

#echo ack $1 --word-regexp --pager="$pager" --type-set="$file_types" "$ign_dirs" "$ign_files" --noenv

Array variation

ack $1 --word-regexp --pager="$pager" --type-set="$file_types" "$ign_dirs" "$ign_files" --noenv

Hardcoded variation

ack $1 --word-regexp --pager=less --type-set=elixir:ext:ex,exs,eex,heex --ignore-dir=dependencies --ignore-dir=test --ignore-dir=config --ignore-file=is:mix.exs --ignore-file=is:credo.exs --noenv

I created the hardcoded variation with the commented out echo line. When I run the hardcoded variation ack works as expected. When I run the array variation it seems as if ack doesn't see the command line options--for example, mix.exs is included although it shouldn't be and it searches the test directory.

Is my shell script wrong? I copy/paste most of the shell script--I mean I can echo $ign_dirs and I see the right value there and when I run the command (the array variation) it doesn't work correctly which seems to indicate that my shell script is fine.

By the way, I'm running this on a mac on zsh. I did test this under bash and I see the same issue.

Apologies in advance if this is some sort of ack FAQ somewhere. I did check but didn't find anything to point to a solution.

EDIT:

I can see that I wasn't as clear as I could have been.

Ultimately I'm trying to automate the searching of Elixir code with ack. I want to keep my options/search within a bash script as much as possible so I won't have to worry about variations in .ackrc files and environment variables on different machines.

What I'm expecting is that when ack searches the files it will exclude the directories I've listed in ignore_dirs as well as skipping the files I've specified in the ignore_files. When I run my shell script with the hardcoded variation, the directories get ignored. When I run my shell script with the array variation they do not get ignored.

And yes, I know that ign_dirs and ign_files are strings not arrays. Is it possible to use the arrays directly on the command line in the shell script?

2 Answers2

4

Build arrays for the --ignore-* options:

ignore_dirs=("dependencies" "test" "config")
ign_dirs=()
for i in "${ignore_dirs[@]}"; do
  ign_dirs+=("--ignore-dir=$i");
done

ignore_files=("is:mix.exs" "is:credo.exs") ign_files=() for i in "${ignore_files[@]}"; do ign_files+=("--ignore-file=$i"); done

Then use those arrays in the command:

ack "$1" --word-regexp --pager="$pager" --type-set="$file_types" "${ign_dirs[@]}" "${ign_files[@]}" --noenv
muru
  • 72,889
1

Remove quotes around your variables in the final command.

ack $1 --word-regexp --pager="$pager" --type-set="$file_types" $ign_dirs $ign_files --noenv

You have multiple space separated pieces in these variables and you want them to be space separated.

The original code (with quotes) expands to:

ack $1 --word-regexp --pager=less --type-set=elixir:ext:ex,exs,eex,heex "--ignore-dir=dependencies --ignore-dir=test --ignore-dir=config" "--ignore-file=is:mix.exs --ignore-file=is:credo.exs"  --noenv

So it is not a set of keys with values, it is two positional parameters.

White Owl
  • 5,129
  • 1
    this will work only as long as the filenames themselves don't contain whitespace (or glob characters, or whatever IFS was set to) – ilkkachu Jul 23 '22 at 09:56
  • Thanks--this also works. But as @ilkkachu pointed out I surrounded the values in quotes because of potential whitespace. – Onorio Catenacci Jul 25 '22 at 12:51