我有一个具有以下格式的电子书目录:
<authorname> <authorsurname> - <bookname>
我想按作者分类书籍。我在 for 循环中使用以下命令进行此操作:
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
我希望看到作者姓氏下一个的值作者姓名值,但这些值会逐行打印。如果我在 for 循环中单独运行 ls 命令,那么它会按我想要的方式运行(输出 1)。但在循环中,它不会运行(输出 2)。
视觉输出:
我想要的是:
Edgar Allan Poe
Marcus Aurelius
会发生什么:
Edgar
Allan
Poe
Marcus
Aurelius
我该如何解决这个问题,并将作者按姓名和姓氏排在同一行?
编辑:我尝试“cat”一个包含作者姓名的文件。但它也没有用。
答案1
的扩展值$(command)
是一个单一的扁平字符串,包含命令输出的所有行。它不是由多行组成的数组。
所有不带引号的 shell 扩展,无论是$variables
还是$(commands)
,都受单词拆分。顾名思义,默认情况下,该值被拆分为单个单词 -不是线条– 根据在 $IFS 中找到的分隔符。
要循环遍历每一行,可以使用mapfile
将输入导入到实际的数组变量(每行作为一个单独的数组元素,稍后可以看到declare -p authors
)...
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.
...或者for
用管道和“读取”循环替换...
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.
...或者完全跳过整个过程并只使用通配符扩展:
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.