Is there a way around broken pipe?
sort: write failed: standard output: Broken pipe
The problem is not between find
and sort
. The sort
has problem with output, which means the shell is not willing to read as long list in a variable.
You'll have to process the input with while read
…, storing it in temporary file if you need it more than once. With the added advantage, that this splits on newline only, so it correctly handles filenames with spaces which the backtick approach does not.
Unfortunately you don't say how you want to use the result, I can't tell you how to exactly rewrite it.
Note, that arrays are not part of POSIX shell specification and there are shells that are noticeably faster than bash, but don't have them. That's why many people, including me, often avoid using them in scripts.
Related videos on Youtube
user1541776
Updated on September 18, 2022Comments
-
user1541776 over 1 year
I have a directory with a large number of files.
./I_am_a_dir_with_many_subdirs/
Within a script I'd like to find all subdirs in it, to sort them and to output to a bash array. So, I do:
SubdirsArray=(`find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort`)
Executing the script, I get the following error messages:
sort: write failed: standard output: Broken pipe sort: write error
As explained in this post: probably
sort
executes and closes the pipe, beforefind
completes writing to it. Thus write() command initiated byfind
gets an error EPIPE "Broken pipe", OS sendsfind
a SIGPIPE. Before the SIGPIPE reachesfind
, it prints the error message, then gets SIGPIPE and dies.Questions:
So, what does my
SubdirsArray
contain? The Subdirs, thatfind
found, butsort
left unsorted?-
If so, than what would be the way around this issue with broken pipes? Make find write it's results to a temporary file and then make sort read it?
I don't understand, why "it's also nothing to be concerned about" if it happens within a non-interactive shell: why? My
SubdirsArray
contains something unsorted and further in the script, I assume, that its elements are sorted?! -
I get two error messages:
sort: write failed: standard output: Broken pipe sort: write error
In this thread it is suggested, that
sort
doesn't have enough space in a temporary directory to sort all the input. But, doesn't it mean, that sort got something from find?!? I'm confused... Anyways, I tried to useSubdirsArray=(`find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort -T /home/temp_dir`)
but it didn't help.
P.S.
I'm not sure whether it's important, but I use
find|sort
in a multi-processor script: several processors execute the same command at once in the subshells.-
Jan Hudec about 10 years
sort
can't do anything before it read the input in full and besides if it was thesort
ending prematurely, it would befind
reporting broken pipe, notsort
. The error in the other thread you mention looks very different and is indeed different. -
user1541776 about 10 years@JanHudec thank you for pointing that out, I didn't pay attention, to what command reported the problem.
-
user1541776 about 10 yearsJan, thank you for the answer and the comment. I'd like to use
SubdirsArray
in a for loop. So, I will implement your solution like:find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort > temp.txt; while read Subdir; do myFunction $Subdir; done; rm temp.txt
In the end, I'd like to applymyFunction
to allSubdirs
. To do it faster, I try to parallelise my code and useN
subshells withwait
. Each subshell should take only it's part of Subdirs. I didn't want to send a long array of Subdirs it should handle to each subshell, but first/last index ofSubdirsArray
. -
Jan Hudec about 10 years@user1541776: Don't forget to redirect input into the loop. It could be done even without temporary file, but probably not if you want to split it first.
-
user1541776 about 10 yearsyou mean
find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort > temp.txt; while read Subdir; do myFunction $Subdir; done
< "temp.txt"; rm temp.txt
? -
Jan Hudec about 10 years@user1541776: Yes, exactly.
read
just reads from standard input. -
Jan Hudec about 10 years@user1541776: You can also pipe to the loop, but it will than run in a subshell, on in shell that has it (like bash, but not ash/dash) you can use process substitution, i.e. like
<(find ... | sort)
. -
user1541776 about 10 yearsthank you. So, the final version would be 1. piping to the loop:
find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort | while read Subdir; do myFunction $Subdir; done
or alternatively 2. using process substitutionwhile read Subdir; do myFunction $Subdir; done <(find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort)
-
Jan Hudec about 10 years@user1541776: Yes.
-
user1541776 about 10 yearsThanks, Jan! Bugfix: while read Subdir; do myFunction $Subdir; done < <(find ./I_am_a_dir_with_many_subdirs/ -maxdepth 2 -mindepth 2 -type d | sort)