0

I want to create a list of mp3 files like a 1.mp3|a 2.mp3.

I have tried echo ${(j:|:)$(echo *.mp3)} and some variations of it, but they don’t work:

# too much splitting 
01|The|Magic|Finger|01.mp3|02|The|Magic|Finger|02.mp3|03|The|Magic|Finger|03.mp3|04|The|Magic|Finger|04.mp3|05|The|Magic|Finger|05.mp3|06|The|Magic|Finger|06.mp3

# too much quoting
01 The Magic Finger 01.mp3 02 The Magic Finger 02.mp3 03 The Magic Finger 03.mp3 04 The Magic Finger 04.mp3 05 The Magic Finger 05.mp3 06 The Magic Finger 06.mp3

I don’t want to create functions or variables for doing this. (It can be trivially done.)

0

3 Answers 3

4

It's a bit silly to get the list of mp3 files, pass them to echo so it can print them separated by spaces, then transfer that output over a pipe, read it, split on space/tab/newline/NUL, and then join with |.

Either do:

printf '%s|' *.mp3

Or

files=(*.mp3)
joined=${(j:|:)files}

If the purpose is for that to be used as a zsh pattern, you'll probably want to escape the wildcard characters in the names of those files. That is done with the b parameter expansion flag:

pattern="(${(j:|:)${(b@)files}})"
0
0

You can use set to glob those files into positional parameters and then "$*" to expand them with your desired field separator:

set -- *.mp3
(IFS=\|; echo "$*")

Note this is being done in a subshell so the changes to IFS don't affect your current shell.

4
  • I know, but I want to do it with substitutions and expansions.
    – HappyFace
    Aug 10, 2019 at 20:31
  • Unnecessary and not as robust but if you really want to you could do set -- $(echo *.mp3). This will break on files with whitespace though. You could also arbitrarily do echo $(IFS=\|; echo "$*") but there is no reason to do that.
    – jesse_b
    Aug 10, 2019 at 20:32
  • I mean I want it done all in one line. Like my own answer. 😅
    – HappyFace
    Aug 10, 2019 at 20:33
  • Virtually any group of shell commands can be done on one line with a liberal application of ;
    – jesse_b
    Aug 10, 2019 at 20:33
0

I have found one way to do this, but it’s still rather convoluted for such a simple use case:

echo ${(j:|:)"${(@f)$(print -l *.mp3)}"}

3
  • This will break on files that contain newlines.
    – jesse_b
    Aug 10, 2019 at 20:35
  • @Jesse_b If we should have a command to print them NUL separated, we can use (@0). I myself don’t have paths with new lines.
    – HappyFace
    Aug 10, 2019 at 20:38
  • 2
    @Jesse_b, or backslash or that start with -. Here, you could do printf '%s\n'. You could do printf '%s\n' ${(j:|:)${(0)"$(printf '%s\0' *.txt)"}}, but again that feels quite silly. Aug 10, 2019 at 20:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.