skip to Main Content

I am running on Ubuntu 24.04.
I created a bash script that reads a file line by line in a loop and asks in this loop for a user input. (In fact it calls a function where this happens and something more, but to simplify my problem, we can ignore that)
Here is a simpel version of my script:

#!/bin/bash

REMOTE_CONFIG_LIST="./files_to_copy.txt"

while IFS=' ' read -r remote_file local_dest
do
        echo
        echo "Line = " "$remote_file" "$local_dest"
        read -p "Please enter your name: " name
        echo "Hello, $name!"
        echo

done < "$REMOTE_CONFIG_LIST"

I understand that the reason for a failure of that script is the fact that the first read is not finished while I start the 2nd read. What are my options here ?

Thanks in advance and best regards

Daniel

Actual result:
Line = /home/azureconf/conf/ubuntu/05-sentinelconnector.conf /etc/rsyslog.d
Hello, /home/azureconf/conf/ubuntu/rsyslog.conf /etc!

Expected result:
Line = /home/azureconf/conf/ubuntu/05-sentinelconnector.conf /etc/rsyslog.d
Please enter your name: Daniel
Hello, Daniel

Line = /home/azureconf/conf/ubuntu/rsyslog.conf /etc
Please enter your name: Daniel
Hello, Daniel

4

Answers


  1. You can direct your file read to use file descriptor 3, rather than the standard which then conflicts when you also ask for the user input. This will keep them separate.

    while read -r -u3
    
    Login or Signup to reply.
  2. Use a dedicated file descriptor:

    Under bash, you could generate temporary unnamed fifo, then link them do a free file descriptor and store his value into a variable by simply: {varname}< syntax:

    #!/bin/bash
    
    REMOTE_CONFIG_LIST="./files_to_copy.txt"
    
    while IFS=' ' read -ru $CONFIG remote_file local_dest; do
        echo
        echo "Line = " "$remote_file" "$local_dest"
        read -p "Please enter your name: " name
        echo "Hello, $name!"
        echo
    done  {CONFIG}< "$REMOTE_CONFIG_LIST"
    
    Login or Signup to reply.
  3. Since you asked for options – if the file or dest are unique then you could always read the file into an associative array first then loop on its contents, e.g. untested

    #!/usr/bin/env bash
    
    REMOTE_CONFIG_LIST="./files_to_copy.txt"
    
    declare -A file2dest
    while IFS=' ' read -r remote_file local_dest; do
            file2dest["$remote_file"]="$local_dest"
    done < "$REMOTE_CONFIG_LIST"
    
    for remote_file in "${!file2dest[@]}"; do
            local_dest="${file2dest[$remote_file]}"
            echo
            echo "Line = " "$remote_file" "$local_dest"
            read -p "Please enter your name: " name
            echo "Hello, $name!"
            echo
    done
    

    Use whichever value is unique as the array index.

    If neither are unique then you could do the same with an indexed array:

    #!/usr/bin/env bash
    
    REMOTE_CONFIG_LIST="./files_to_copy.txt"
    
    declare -a file_dest
    while IFS= read -r line; do
            file_dest+=( "$line" )
    done < "$REMOTE_CONFIG_LIST"
    
    for line in "${file_dest[@]}"; do
            remote_file="${line% *}"
            local_dest="${line#* }"
            echo
            echo "Line = " "$remote_file" "$local_dest"
            read -p "Please enter your name: " name
            echo "Hello, $name!"
            echo
    done
    
    Login or Signup to reply.
  4. Another approach would be to preload the file.
    That’s not a great idea if it’s very big, but if you are prompting the user on every line I assume it isn’t millions or even hundreds of lines, so this approach should be simple and workable.

    REMOTE_CONFIG_LIST="./files_to_copy.txt"
    mapfile -t list < "$REMOTE_CONFIG_LIST" # load the whole file to an array
    for line in "${list[@]}"               # loop over the array
    do  remote_file="${line% *}"           # parse out the first field
        local_dest="${line#* }"            # parse out the second field
        echo "Line = $remote_file $local_dest"
        read -p "Please enter your name: " name
        printf "Hello, %s!nn" "$name"
    done
    

    This smacks strongly of an X/Y Problem, though.
    You might get better answers if you explain what you are trying to accomplish.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search