Need alternative to readarray/mapfile for script on older version of Bash Need alternative to readarray/mapfile for script on older version of Bash unix unix

Need alternative to readarray/mapfile for script on older version of Bash


You can loop over your input and append to the array:

$ while IFS= read -r line; do arr+=("$line"); done < <(printf '%d\n' {0..5})$ declare -p arrdeclare -a arr='([0]="0" [1]="1" [2]="2" [3]="3" [4]="4" [5]="5")'

Or, for your specific case:

while IFS= read -r line; do    drives+=("$line")done < <(lsblk --nodeps -o name,serial,size | grep "sd")

See the BashFAQ/001 for an excellent explanation why IFS= read -r is a good idea: it makes sure that whitespace is conserved and backslash sequences not interpreted.


Here's the solution I came up with a while back. This is better because it provides a substitute function for older versions of Bash that don't support mapfile/readarray.

if ! type -t readarray >/dev/null; then  # Very minimal readarray implementation using read. Does NOT work with lines that contain double-quotes due to eval()  readarray() {    local cmd opt t v=MAPFILE    while [ -n "$1" ]; do      case "$1" in      -h|--help) echo "minimal substitute readarray for older bash"; exit; ;;      -r) shift; opt="$opt -r"; ;;      -t) shift; t=1; ;;      -u)           shift;           if [ -n "$1" ]; then            opt="$opt -u $1";             shift          fi          ;;      *)          if [[ "$1" =~ ^[A-Za-z_]+$ ]]; then            v="$1"            shift          else            echo -en "${C_BOLD}${C_RED}Error: ${C_RESET}Unknown option: '$1'\n" 1>&2            exit          fi          ;;      esac    done    cmd="read $opt"    eval "$v=()"    while IFS= eval "$cmd line"; do            line=$(echo "$line" | sed -e "s#\([\"\`]\)#\\\\\1#g" )      eval "${v}+=(\"$line\")"    done  }fi

You don't have to change your code one bit. It just works!

readarray -t services -u < <(lsblk --nodeps -o name,serial,size | grep "sd")