9

Say, for example, I have the following array:

files=( "foo" "bar" "baz fizzle" )

I want to pipe the contents of this array through a command, say sort, as though each element where a line in a file. Sure, I could write the array to a temporary file, then use the temporary file as input to sort, but I'd like to avoid using a temporary file if possible.

If "bar fizzle" didn't have that space character, I could do something like this:

echo ${files[@]} | tr ' ' '\012' | sort

Any ideas? Thanks!

5 Answers 5

11
sort <(for f in "${files[@]}" ; do echo "$f" ; done)
Sign up to request clarification or add additional context in comments.

3 Comments

Perfect! I didn't know about the <() syntax. Thanks Ignacio!
I also didn't know (until now) that "${files[@]}" expands to "foo" "bar" "baz fizzle" rather than "foo bar baz fizzle".
What is this particular method called?
7

Yet another solution:

printf "%s\n" "${files[@]}" | sort

2 Comments

Although this works, it seems to rely on poorly documented behavior of printf: the fact that, unlike in the C version of printf, the printf command line utility loops over the format string until there are no more arguments. If you look at the man page for printf(1) under Mac OS X, it talks about this in the BUGS section. I'll still give you the vote though ;)
@splicer: I think the note in the BUGS section is talking about something else; the main DESCRIPTION section says "The format string is reused as often as necessary to satisfy the arguments." The bash(1) man page has a similar note on its printf builtin.
3
SAVE_IFS=$IFS
IFS=$'\n'
echo "${files[*]}" | sort
IFS=$SAVE_IFS

Of course it won't work properly if there are any newlines in array values.

Comments

2

For sorting files I would recommend sorting in zero-terminated mode (to avoid errors in case of embedded newlines in file names or paths):

files=(
$'fileNameWithEmbeddedNewline\n.txt'
$'saneFileName.txt'
)

echo ${#files[@]}

sort <(for f in "${files[@]}" ; do printf '%s\n' "$((i+=1)): $f" ; done)
sort -z <(for f in "${files[@]}" ; do printf '%s\000' "$((i+=1)): $f" ; done) | tr '\0' '\n'

printf "%s\000" "${files[@]}" | sort -z | tr '\0' '\n'
find . -type f -print0 | sort -z | tr '\0' '\n'

sort -z reads & writes zero-terminated lines!

1 Comment

@splicer NUL-terminated is still safest for lists of data, many programs are capable of using & producing them.
1

I like to wrap common items like this into function to make it easier to understand what's going on:

pipeArray() {
    for ITEM in $@; do
        echo "$ITEM"
    done
}

DATA=('a' 'c' 'b')
pipeArray ${DATA[@]} | sort

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.