简体   繁体   English

Bash:在遍历字符串数组后无法读出带空格的字符串

[英]Bash: cant' read out strings with spaces after looping through array of strings

I am using a loop to read the contents of an array, which contains all of the directories and files in the directory hierarchy called 'music' (contents are strings from the previous output of 'find' command).我正在使用循环来读取数组的内容,该数组包含名为“音乐”的目录层次结构中的所有目录和文件(内容是来自“查找”命令的先前 output 的字符串)。 The idea is to separate the full directory path of each array element in "directory_contents" into substrings according to genre, artist, and title.这个想法是根据流派、艺术家和标题将“directory_contents”中每个数组元素的完整目录路径分成子字符串。 Since my music directory is sorted first by genre, then by artist, then by title, I am grabbing each relevant item using awk where the delimiter "/" shows up.由于我的音乐目录首先按流派排序,然后按艺术家排序,然后按标题排序,因此我使用 awk 抓取每个相关项目,其中分隔符“/”出现。 For example, if the directory looks like this after using find "./Electronic/Squarepusher/My Red Hot Car.aif", I will separate "Electronic", "Squarepusher", and "My Red Hot Car", then store them each in separate arrays for genre, artist, and title.例如,如果使用 find "./Electronic/Squarepusher/My Red Hot Car.aif" 后目录看起来像这样,我将把 "Electronic"、"Squarepusher" 和 "My Red Hot Car" 分开,然后分别存储在单独的 arrays 中用于流派、艺术家和标题。 Later I will sort these data, then pipe the sorted output into another utility to print all the directory contents in a nice looking table (haven't done this yet).稍后我将对这些数据进行排序,然后将 pipe 排序后的 output 放入另一个实用程序中,以在一个漂亮的表中打印所有目录内容(还没有这样做)。 For now, I am just trying to view the results of the string separation with echo statements, and for the most part it seems to work.目前,我只是尝试使用 echo 语句查看字符串分离的结果,并且在大多数情况下它似乎有效。 However, I can't seem to extract substrings which contain spaces, which isn't good:但是,我似乎无法提取包含空格的子字符串,这不好:

-->./Hip-Hop/OutKast/title1.aif<--
Genre:
Hip-Hop
Artist:
OutKast
Title:
title1

-->./Hip-Hop/OutKast/title2.aif<--
Genre:
Hip-Hop
Artist:
OutKast
Title:
title2

-->./Hip-Hop/OutKast/title3.aif<--
Genre:
Hip-Hop
Artist:
OutKast
Title:
title3

-->./Jazz/John<--
Genre:
Jazz
Artist:
John
Title:


-->Coltrane/title1.aif<--
Genre:
title1.aif
Artist:

Title:

As you can see, when the loop reads in the string "John Coltrane", it is treating the space as a delimiter, and treating everything after "John" as a different filename.如您所见,当循环读取字符串“John Coltrane”时,它将空格视为分隔符,并将“John”之后的所有内容视为不同的文件名。 I tried looking for a solution in the bash manual under the section "Arrays" as well as other posts here, but couldn't find a solution that worked for my specific problem (sorry).我尝试在 bash 手册中的“阵列”部分以及此处的其他帖子中寻找解决方案,但找不到适合我的特定问题的解决方案(抱歉)。 If anyone has ideas, they would be greatly appreciated.如果有人有想法,他们将不胜感激。 The problematic code appears below, in the for loop (I didn't post the whole script because it is pretty lengthy, but let me if it is needed):有问题的代码出现在下面的 for 循环中(我没有发布整个脚本,因为它很长,但如果需要,请告诉我):

#more before this...

#declare variables                                                                                                      
declare -a genre_list                                                                                                   
declare -a title_list                                                                                                   
declare -a artist_list                                                                                                  
declare -a directory_contents                                                                                           


#populate directory with contents                                                                                       
cd $directory                                                                                                           
directory_contents=$(find .  -mindepth 1 -type f)                                                                       
cd ..                                                                                                                   


for music_file in ${directory_contents[*]}; do                                                                          
    if [[ $DEBUG = "true" ]] ; then                                                                                     
        echo "-->$music_file<--"                                                                                        
    fi                                                                                                                  

    echo "Genre:"                                                                                                       
    echo $music_file | awk -F"/" '{print $2}'                                                              
    echo "Artist:"                                                                                                      
    echo $music_file | awk -F"/" '{print $3}'                                                               
    echo "Title:"                                                                                                       
    echo $music_file | awk -F"/" '{print $4}' | awk -F"." '{print $1}'                                     
    echo ""                                                                                                             
done   

Why don't you simply do it in single line:你为什么不简单地在单行中做:

cd $directory && \
find .  -mindepth 3 -maxdepth 3 -type f | \ 
awk -F'/' '{split($4,A,".aif"); printf "Genre: %s\nArtist: %s\nTitle: %s\n\n",$2,$3,A[1];}'

Update: (removed the .aif from the Title part)更新:(从标题部分中删除了.aif

If you can, you should use Perl for this task:如果可以,您应该使用 Perl 来完成此任务:

#! /usr/bin/perl

foreach my $fname (<*/*/*>) {
  next unless -f $fname;
  next unless $fname =~ m"^([^/]+)/([^/]+)/([^/.]+)\.\w+$";
  my ($genre, $artist, $title) = ($1, $2, $3);
  printf("Genre: %s\nArtist: %s\nTitle: %s\n\n", $genre, $artist, $title);
}

It is faster and simpler than the shell, and it is immune against whitespace in file names.它比 shell 更快、更简单,并且不受文件名中的空格的影响。

MUSICDIR="/some/path"
cd "$MUSICDIR"

find  . -type f -print | (IFS=/;while read dot genre artist title
do
    echo =$genre= =$artist= =$title=
done)

You might try setting the delimiter that bash uses.您可以尝试设置 bash 使用的分隔符。 Perhaps to a newline character?也许换行符?

IFS=\n

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM