Search code examples
shellparsingshkshifs

Parsing a shell command output into two variables by line


I'm writing a script that outputs a bar graph of the sizes of the files/directories in a directory. I'm currently getting the required data with the line

array=($(du -sc * | sort -hr))

which results in every other line of array being a size and every other line a filename corresponding to it. However, if any of the filenames contain spaces, this naive approach doesn't work because the output is split at every space.

Basically what I want to do is parse the output line by line so that from each line I first get the characters up to the first space (the size), and then the rest of the line (the filename, which may or may not contain spaces). I thought about alternating the IFS between a space and a newline, but couldn't think of how exactly I would do that.

I'd prefer the solution to be portable between different shells, or at least to work in ksh.


Solution

  • The way to read line by line is a while read loop, and read allows reading multiple fields:

    names=() sizes=()
    
    while read -r size name
    do
        echo "The file '$name' has size $size"
        names+=("$name")
        sizes+=("$size")
    done < <(du -sc ./* | sort -hr)
    

    The ./* prevents problems with files starting with dashes (for du) and leading spaces (for read).