Search code examples
stringbashinsert

How to insert string (or character) into another string at specified index position in bash?


There are similar questions:

But they ask to solve some specific problems, not to get general solution.

How should look function in bash scripting for inserting string (or char) into another string at specified index? Performance optimized solutions are welcome in the first place.

Examples with input parameters and expected results for the required function / procedure:

string: "/etc /bin"
string to insert: "/tmp "
position index to insert: 0 (beginning of string)
expected result: "/tmp /etc /bin"

string: "/etc /bin"
char to insert: "|"
position index to insert: 2
expected result: "/e|tc /bin"

string: "/tmp /etc"
string to insert: " /bin"
position index to insert: 9 (end of string)
expected result: "/tmp /etc /bin"

string: "/tmp /etc /bin"
string to insert: "[ ]"
position index to insert: 7
expected result: "/tmp /e[ ]tc /bin"

Related question:


This question is part of the project related to my another question: How to retrieve text from the current line at specified cursor position before and after up to specified boundary characters?


Solution

  • cat insert_at_position.sh
    
    #!/bin/bash
    
    insert_at_position() {
        local input_string=$1; shift
        local insert_string=$1; shift
        local position=$1; shift
        local result="${input_string:0:$position}$insert_string${input_string:$position}"
        echo "$result"
    }
    
    assert_equals() {
        local error_message=$1; shift
        local expected_result=$1; shift
        local actual_result=$1; shift
    
        if [ "$expected_result" != "$actual_result" ]; then
            printf "%s\n" "$error_message; Expected: $expected_result; Actual: $actual_result"
        fi
    }
    
    test_insert_at_position() {
        local test_line="/etc /bin"
        local expected="/e|tc /bin"
        local actual=$(insert_at_position "$test_line" "|" 2)
        assert_equals "test_insert_cursor_char-p2 failed" "$expected" "$actual"
    
        local test_line="/tmp /etc"
        local expected="/tmp /etc /bin"
        local actual=$(insert_at_position "$test_line" " /bin" 9)
        assert_equals "test_insert_cursor_char-p9 failed" "$expected" "$actual"
    
        local test_line="/tmp /etc /bin"
        local expected="/tmp /e[ ]tc /bin"
        local actual=$(insert_at_position "$test_line" "[ ]" 7)
        assert_equals "test_insert_cursor_char-p7 failed" "$expected" "$actual"
    
        local test_line="/etc /bin"
        local expected="/tmp /etc /bin"
        local actual=$(insert_at_position "$test_line" "/tmp " 0)
        assert_equals "test_insert_cursor_char-p0 failed" "$expected" "$actual"
    
        local test_line="/etc /bin"
        local expected="/tmp"
        local actual=$(insert_at_position "$test_line" "/tmp " 0)
        assert_equals "test_insert_cursor_char - here fail is expected" "$expected" "$actual"
    }
    
    test_insert_at_position
    
    
    • insert_at_position - function that inserts string into string at specified index
    • test_insert_at_position - unit tests for this function
    • assert_equals - used in test_insert_at_position, shows error message if particular unit test failed.

    Below the same function but made as procedure with out_result parameter that contains result. Calling it does not require Command Substitution $() and associated subshell creation. But nonetheless performance of this functions is about the same.

    cat insert_at_position.sh
    
    #!/bin/bash
    
    assert_equals() {
        local error_message=$1; shift
        local expected_result=$1; shift
        local actual_result=$1; shift
    
        if [ "$expected_result" != "$actual_result" ]; then
            printf "%s\n" "$error_message; Expected: $expected_result; Actual: $actual_result"
        fi
    }
    
    insert_at_position() {
        local input_string=$1; shift
        local insert_string=$1; shift
        local position=$1; shift
        declare -n out_result=$1; shift
        out_result="${input_string:0:$position}$insert_string${input_string:$position}"
    }
    
    test_insert_at_position() {
        test_line="/etc /bin"
        expected="/e|tc /bin"
        insert_at_position "$test_line" "|" 2 actual
        assert_equals "test_insert_cursor_char-p2 failed" "$expected" "$actual"
    
        test_line="/tmp /etc"
        expected="/tmp /etc /bin"
        insert_at_position "$test_line" " /bin" 9 actual
        assert_equals "test_insert_cursor_char-p9 failed" "$expected" "$actual"
    
        test_line="/tmp /etc /bin"
        expected="/tmp /e[ ]tc /bin"
        insert_at_position "$test_line" "[ ]" 7 actual
        assert_equals "test_insert_cursor_char-p7 failed" "$expected" "$actual"
    
        test_line="/etc /bin"
        expected="/tmp /etc /bin"
        insert_at_position "$test_line" "/tmp " 0 actual
        assert_equals "test_insert_cursor_char-p0 failed" "$expected" "$actual"
    
        test_line="/etc /bin"
        expected="/tmp"
        insert_at_position "$test_line" "/tmp " 0 actual
        assert_equals "test_insert_cursor_char - here fail is expected" "$expected" "$actual"
    }
    
    test_insert_at_position