1

Given an array of strings, I want IFS to parse each string by an underscore, join the first three separated values together using the same delimeter and output them to an empty list. For instance, if I have the array input=("L2Control_S3_L001_R1_001.fastq", "L2Control_S3_L001_R2_001.fastq") IFS would take the first string and separate it out by the underscore, so the output would be:

L2Control
S3
L001
R1
001.fastq

Afterward, it would take the first three separated values and join them together with an underscore: "L2Control_S3_L001". Lastly, this value would be appended onto a new array output=("L2Control_S3_L001") this process would continue until all values in the array are completed. I have tried the below implementation, but it seems to run infinitely.

#!/bin/bash

str=("L2Control_S3_L001_R1_001.fastq", "L2Control_S3_L001_R1_001.fastq")

IFS='_'
final=()

for (( c = 0; c = 2; c++ )); do
  read -ra  SEPA <<< "${str[$c]}"
  final+=("${SEPA[0]}_${SEPA[1]}_${SEPA[2]}")
done

Can someone help me with this, please?

6
  • 1
    Your for loop is not correct. The middle condition should be something like c < ${#str[@]} Commented Apr 2, 2022 at 18:34
  • 1
    (1) Don't use a , to separate array elements -- that comma is ending up as part of your data. (2) Note that you can set IFS local to a single read command. IFS=_ read -r -a arrayname won't change IFS for any command other than that read. Commented Apr 2, 2022 at 18:34
  • BTW, I don't see a reason to use read -a at all when you expect exactly three pieces. IFS=_ read -r first second third will put the first piece in "$first", the second in "$second", everything after the second in "$third" and there you are. Commented Apr 2, 2022 at 18:35
  • And why use a counter c at all? for a_str in "${str[@]}"; do will assign each piece to a_str in turn. Commented Apr 2, 2022 at 18:36
  • ...but anyhow, none of the problems I see this code having have anything to do with IFS. If I'm missing something that is IFS-specific, could you explain more clearly? Commented Apr 2, 2022 at 18:36

3 Answers 3

1

The ${array[*]} expansion joins elements using the first character of IFS. You can combine this with the ${var:offset:length} expansion.

output=()
for str in "${input[@]}"; do
    read -ra fields <<< "$str"
    output+=("${fields[*]:0:3}")
done

I find declare -p varname ... handy to inspect the contents of variables.


This can also be done with bash parameter expansion:

str="L2Control_S3_L001_R1_001.fastq"
IFS=_
suffix=${str#*"$IFS"*"$IFS"*"$IFS"}
first3=${str%"$IFS$suffix"}
declare -p str suffix first3
declare -- str="L2Control_S3_L001_R1_001.fastq"
declare -- suffix="R1_001.fastq"
declare -- first3="L2Control_S3_L001"

Can also do that in one line, but it's hairy:

first3="${str%"$IFS${str#*"$IFS"*"$IFS"*"$IFS"}"}"
Sign up to request clarification or add additional context in comments.

2 Comments

I tried to do your following example using: input=("L2Control_S3_L001_R1_001.fastq" "L2Control_S3_L001_R2_001.fastq") output=() for str in "${input[@]}"; do read -ra feilds <<< "$str" output+=("${feilds[*]:0:2}") done for str_a in "${output[@]}"; do echo "$str_a" done However it just printed out the samething that was in the input: "L2Control_S3_L001_R1_001.fastq" "L2Control_S3_L001_R2_001.fastq"
When testing that, did you set IFS=_
1

Setup (notice no comma needed to separate array entries):

str=("L2Control_S3_L001_R1_001.fastq" "L2Control_S3_L001_R1_001.fastq")

One idea using a while/read loop to parse the input strings into 4 parts based on a delimiter (IFS=_):

final=()

while IFS=_ read -r f1 f2 f3 ignore
do
    final+=("${f1}_${f2}_${f3}")
done < <(printf "%s\n" "${str[@]}")

typeset -p final

Where the variable ignore will be assigned fields #4-#n.

This generates:

declare -a final=([0]="L2Control_S3_L001" [1]="L2Control_S3_L001")

Comments

0

That's a lengthy description of taking the first 3 elements separated by _.

printf "%s\n" "${str[@]}" | cut -d_ -f-3

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.