1

I am in a situation similar to this one and having difficulties implementing this kind of solution for my situation.

I have file.tsv formatted as follows:

x     y
dog     woof
CAT     meow
loud_goose     honk-honk
duck     quack

with a fixed number of columns (but variable rows) and I need to loop those pairs of values, all but the first one, in a script like the following (pseudocode)

for elements in list; do
    ./script1 elements[1] elements[2]
    ./script2 elements[1] elements[2]
done

so that script* can take the arguments from the pair and run with it.

Is there a way to do it in Bash?

I was thinking I could do something like this:

list1={`awk 'NR > 1{print $1}' file.tsv`}
list2={`awk 'NR > 1{print $2}' file.tsv`}

and then to call them in the loop based on their position, but I am not sure on how.

Thanks!

2 Answers 2

2

Shell tables are not multi-dimensional so table element cannot store two arguments for your scripts. However since you are processing lines from file.tsv, you can iterate on each line, reading both elements at once like this:

#!/usr/bin/env sh

# Populate tab with a tab character
tab="$(printf '\t')"

# Since printf's sub-shell added a trailing newline, remove it
tab="${tab%?}"

{
  # Read first line in dummy variable _ to skip header
  read -r _

  # Iterate reading tab delimited x and y from each line
  while IFS="$tab" read -r x y || [ -n "$x" ]; do
    ./script1 "$x" "$y"
    ./script2 "$x" "$y"
  done
} < file.tsv # from this file
Sign up to request clarification or add additional context in comments.

2 Comments

I think that should do, thanks, I will test it now. Do you mind if I ask what || [ -n "$x" ] does in the condition?
In case the last line of the file does not end with a newline character, the read command will return failure while still reading the x and y fields. || [ -n "$x" ] tests that variable x is not empty (has been read). → read x y successfully or check x is not empty
0

You could try just a while + read loop with the -a flag and IFS.

#!/usr/bin/env bash

while IFS=$' \t' read -ra line; do
  echo ./script1 "${line[0]}" "${line[1]}"
  echo ./script2 "${line[0]}" "${line[1]}"
done < <(tail -n +2 file.tsv)

Or without the tail

#!/usr/bin/env bash

skip=0 start=-1

while IFS=$' \t' read -ra line; do
  if ((start++ >= skip)); then
    echo ./script1 "${line[0]}" "${line[1]}"
    echo ./script2 "${line[0]}" "${line[1]}"
  fi
done < file.tsv

  • Remove the echo's if you're satisfied with the output.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.