phasstw
phasstw

Reputation: 21

Read each line of a .txt file into an array in bash/shell/unix in Mac OS X without readarray or mapfile commands

I am working on a simple catalog program for my personal library in bash/shell. I am developing in OS X and am stuck on how I am supposed to configure my program without access to UNIX commands such as readarray or mapfile.

Here is the logic of what I am trying to do:

Here is what I wanted to do with mapfile

init_catalog(){
    #read catalog entries into arrays
    printf "%s\n" "Loading catalog..."
    mapfile -t TITLES < titles.txt
    mapfile -t AUTHORS < authors.txt
    mapfile -t EDITORS < editors.txt
    mapfile -t PUB_NAMES < pub-names.txt
    mapfile -t PUB_LOCATIONS < pub-locations.txt
    mapfile -t PUB_DATES < pub-dates.txt
    mapfile -t PAGE_COUNTS < page-counts.txt
    mapfile -t GENRES < genres.txt
    mapfile -t ISBN_NUMS < isbn-nums.txt
    printf "%s\n" "Catalog loaded..."
    INITIALIZED="true"
}

save_catalog_entry(){
    clear
    printf "%s\n\n" "You have entered the following information for this work:"
    printf "%s\n" "PENDING ENTRIES FOR THIS WORK..."
    underline_above_text
    printf "Title: $WORK_TITLE\n"
    printf "Author(s): $WORK_AUTHOR\n"
    printf "Editor(s): $WORK_EDITOR\n"
    printf "Publisher: $WORK_PUB_NAME\n"
    printf "Publication Location: $WORK_PUB_LOCATION\n"
    printf "Publication Date: $WORK_PUB_DATE\n"
    printf "Page Count: $WORK_PAGE_COUNT\n"
    printf "Genre: $WORK_GENRE\n\n"
    underline_above_text
    printf "%s\n" "Is this information correct? If yes, all pending entries for this work will be saved to catalog. If no, all pending entries for this work will be discarded."
    yes_or_no
    if [ $USER_INPUT_YES_NO == "true" ]
    then
        #save input to catalog files
        printf "%s\n" "${TITLES[@]}" > titles.txt
        printf "%s\n" "${AUTHORS[@]}" > authors.txt
        printf "%s\n" "${EDITORS[@]}" > editors.txt
        printf "%s\n" "${PUB_NAMES[@]}" > pub-names.txt
        printf "%s\n" "${PUB_LOCATIONS[@]}" > pub-locations.txt
        printf "%s\n" "${PUB_DATES[@]}" > pub-dates.txt
        printf "%s\n" "${PAGE_COUNTS[@]}" > page-counts.txt
        printf "%s\n" "${GENRES[@]}" > genres.txt
        printf "%s\n" "${ISBN_NUMS[@]}" > isbn-nums.txt
    else
        DISCARDING_ENTRIES="true"
        printf "%s\n" "All input information for this work has been discarded. Please, try again."
    fi
}

Does anyone know which UNIX commands I should/can use to access these config files from the shell, read their contents into arrays, and then save the new content of the arrays back into the .txt config files? Thanks for the help!

Upvotes: 2

Views: 3204

Answers (1)

lynxlynxlynx
lynxlynxlynx

Reputation: 1433

You can use the normal array construction methods (arr[n]="asdas" and arr=( "123" 45 "ss gg" )). Consider this titles.txt file:

once upon a time
pink "cherry" troubles
obfuscator 2

Just read it into a variable by either using bash's f=$(<filename) construct (older than mapfile, so you should have it) or other tools like cat. Then you can iterate over it in a while read loop and save the lines to an array. If you don't need the variable, you can also just read the file in the loop (...; done < filename). Saving back would be done in a similar manner, just looping over the array instead and either using >> to append individually or redirecting the whole loop, where you can use a normal empty-and-fill >.

Approach 2 To skip the explicit loop, read the file to an array by splitting it into whitespace separated pieces first:

oifs=$IFS # save a copy of the input field separator character list
IFS=$'\n' arr=( $(< titles.txt) )
IFS=$oifs # restore
$ echo "${arr[@]}"
once upon a time pink "cherry" troubles obfuscator 2
$ echo "${arr[1]}"
pink "cherry" troubles

Or if you want to also mark the titles' boundaries more obviously, you can quote them:

oifs=$IFS
IFS=$'\n' arr=( $(sed -n 's,",\\",g; s,^.*$,"&",p' titles.txt) )
IFS=$oifs
$ echo "${arr[@]}"
"once upon a time" "pink \"cherry\" troubles" "obfuscator 2"
$ echo "${arr[1]}"
"pink \"cherry\" troubles"

Upvotes: 1

Related Questions