Use awk command to output of ls command

0

I have a e-book directory that has following format:

<authorname> <authorsurname> - <bookname>

I want to separate the books by authors. I use the below command in a for-loop for this operation:

for author in $(ls /home/me/books | awk -F "-" '{print $1}' | sort | uniq)
do
    make a directory and push all books of this author to this directory 
done

I expect to see authorsurname value on next of authorname value but these values getting printed line by line. If I run the ls command that in the for-loop as individual this time it runs as I want (output 1). But in a loop, it doesn't (output 2).

Visually Output:

What I want:

Edgar Allan Poe
Marcus Aurelius

What happens:

Edgar
Allan
Poe
Marcus
Aurelius

How can I fix this issue and sort the authors as name and surname in same line?

Edit: I tried "cat" a file that contains author names. But it didn't work too.

Gefolge

Posted 2019-07-11T10:57:02.527

Reputation: 555

Why not parse ls? – Cyrus – 2019-07-13T17:32:11.680

Answers

1

The expanded value of $(command) is a single flat string containing all lines of the command's output. It is not a multi-element array of individual lines.

All unquoted shell expansions, whether $variables or $(commands), are subject to word splitting. As the name implies, by default the value is split into individual words – not lines – based on the separators found in $IFS.

To loop over each line, either use mapfile to import input into an actual array variable (with each line as a separate array element, as can be seen in declare -p authors later)...

mapfile -t authors < <(ls | awk)

for author in "${authors[@]}"; do
    ...
done

# Note that the < and the <() are two independent operators.
# < <() is used instead of ls|awk|mapfile because pipeline elements
# run in their own scope and cannot alter "parent" variables.

...or replace for with a pipeline and a 'read' loop...

ls | awk | while read -r author; do
    ...
done

# In this case, using a pipeline is okay as long as the 'while' loop
# doesn't need to make variable modifications that remain after the loop.

...or skip the whole thing entirely and just use wildcard expansion:

for book in /home/me/books/*; do
    filename=${book##*/}
    author=${filename%% - *}
    make a $author directory if needed, then move this one book to that directory
done

# Expansions within the right-hand side of a variable assignment
# are actually exempt from word splitting, so they can remain unquoted.

user1686

Posted 2019-07-11T10:57:02.527

Reputation: 283 655