-1

I have a string say, test_var=ab_c_de_fg_.txt. I need to store ab_c in one variable (characters before the 2nd _) and de_fg_ in a second variable (characters after the second _ and before .txt), so these two variables can be used in further operations.

test_var=ab_c_de_fg_.txt for ((i=0;i<{#test_var};i++)) do a[$i]="${var:$i:1}" done flag=0 temp=0 while [["$temp" -le "${#test_var}"]] do if a[temp] -eq "_" && flag -eq 0 flag = 1 continue fi if a[temp] -eq "_" && flag -eq 1 #var1=arr[0] to arr[$(temp-1)] #var2=arr[$(temp+1)] to arr[#(test_var)] fi temp=$((temp+1)) done 

Please guide me, since I am new to shell scripting. Thanks.

6
  • 1
    You mention an array, but there is no array here. And your code is full of errors, don't you get error messages when you try to run this? What is that script supposed to be doing? It doesn't seem to have any relation to what you describe in your question.
    – terdon
    CommentedJun 29, 2020 at 9:14
  • 1
    You already got some ready-made answers, but if you want to get that script or any other into even a remotely working condition, I'd suggest starting small, building it in pieces, and testing each piece before proceeding. Some useful that immediately came to mind: shellcheck.net and unix.stackexchange.com/questions/134472/… Also, fix the indentation. Having it messed up makes it really hard to read what the script is doing.
    – ilkkachu
    CommentedJun 29, 2020 at 9:27
  • @terdon, the first loop would create an array made of the individual characters of the variable (if the missing $ was added before {#test_var})CommentedJun 29, 2020 at 9:29
  • @terdon, ... and there's the general idea of processing the string character-by-character, checking for the _ separator etc. Looks a bit like what someone might write in C to do that.
    – ilkkachu
    CommentedJun 29, 2020 at 9:31
  • @StéphaneChazelas yes, but as you say, the individual characters so not what the OP seems to want.
    – terdon
    CommentedJun 29, 2020 at 9:50

2 Answers 2

2

To split a string into an array, you can use the split+glob operator (invoked when you leave a parameter expansion unquoted in list context):

test_var=ab_c_de_fg_.txt root_name=${test_var%.*} # remove extension IFS=_ # split on _ set -o noglob # disable glob part array=( $root_name"" ) # split+glob, preserve empty trailing element if any 

typeset -p array would then show something like:

typeset -a array=(ab c de fg '') 

To join elements of an array with the first character (byte in ksh) of $IFS, you do "${array[*]}".

So:

printf '%s\n' "${array[*]:0:2}" "${array[*]:2}" 

Would output:

ab_c de_fg_ 

And your two variables could be defined like:

first_part="${array[*]:0:2}" second_part="${array[*]:2}" 
    1

    Here's one way to do what your question asks for in bash (and ignoring your code, since I can't understand what you're trying to do with it):

    $ test_var=ab_c_de_fg_.txt $ read var1 var2 < <(echo "$test_var" | sed 's/_/ /2; s/\.txt$//') $ echo "$var1" ab_c $ echo "$var2" de_fg_ 

    In a script, that would just be:

    test_var=ab_c_de_fg_.txt read var1 var2 < <(echo "$test_var" | sed 's/_/ /2; s/\.txt$//') 

    And you now have $var1 and $var2.

    The trick is using read to read the two variables. That will split its input on the current value of the environment variable IFS (which, by default, is a space a tab and a newline). The sed command will replace the 2nd _ with a space (s/_/ /2) and remove the .txt from the end of its input (s/\.txt$//), so what is passed to read will be ab_c de_fg_.txt, and because there is a space in the middle, each string is saved in in the corresponding variable.

    1
    • Note that it assumes $test_var doesn't contain backslashes, SPC, TAB, newline characters and depending on the echo flavour is not something like -n, -Een...CommentedJun 29, 2020 at 9:26

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.