重击:不能'循环遍历字符串数组后读出带空格的字符串

发布于 2024-11-09 05:04:06 字数 3531 浏览 0 评论 0原文

我正在使用循环读取数组的内容,该数组包含名为“music”的目录层次结构中的所有目录和文件(内容是“find”命令先前输出的字符串)。这个想法是根据流派、艺术家和标题将“directory_contents”中每个数组元素的完整目录路径分成子字符串。由于我的音乐目录首先按流派排序,然后按艺术家排序,然后按标题排序,因此我使用 awk 获取每个相关项目,其中分隔符“/”显示。例如,如果使用find“./Electronic/Squarepusher/My Red Hot Car.aif”后目录看起来像这样,我将把“Electronic”、“Squarepusher”和“My Red Hot Car”分开,然后将它们分别存储在流派、艺术家和标题的单独数组中。稍后我将对这些数据进行排序,然后将排序后的输出通过管道传输到另一个实用程序中,以在一个漂亮的表格中打印所有目录内容(尚未这样做)。现在,我只是尝试使用 echo 语句查看字符串分隔的结果,并且在大多数情况下它似乎有效。但是,我似乎无法提取包含空格的子字符串,这不好:

-->./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:

如您所见,当循环读取字符串“John Coltrane”时,它将空格视为分隔符,并处理之后的所有内容“John”作为不同的文件名。我尝试在 bash 手册的“数组”部分以及此处的其他帖子中寻找解决方案,但找不到适合我的特定问题的解决方案(抱歉)。如果有人有想法,他们将不胜感激。有问题的代码出现在下面的 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   

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). The idea is to separate the full directory path of each array element in "directory_contents" into substrings according to genre, artist, and title. 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. 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. 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). 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. 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. 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). 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):

#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   

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

执笏见 2024-11-16 05:04:06

为什么不简单地用单行来做:

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];}'

更新:(从标题部分删除.aif

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)

波浪屿的海角声 2024-11-16 05:04:06

如果可以的话,您应该使用 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);
}

它比 shell 更快、更简单,并且不受文件名中空格的影响。

If you can, you should use Perl for this task:

#! /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.

梦里南柯 2024-11-16 05:04:06
MUSICDIR="/some/path"
cd "$MUSICDIR"

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

find  . -type f -print | (IFS=/;while read dot genre artist title
do
    echo =$genre= =$artist= =$title=
done)
泪冰清 2024-11-16 05:04:06

您可以尝试设置 bash 使用的分隔符。也许换行符?

IFS=\n

You might try setting the delimiter that bash uses. Perhaps to a newline character?

IFS=\n
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文