Find order by name linux

Sorting the output of «find -print0» by piping to the «sort» command

I need to be able to alphabetically sort the output of find before piping it to a command. Entering | sort | between didn’t work, so what could I do?

find folder1 folder2 -name "*.txt" -print0 | xargs -0 myCommand 

6 Answers 6

Use find as usual and delimit your lines with NUL. GNU sort can handle these with the -z switch:

find . -print0 | sort -z | xargs -r0 yourcommand 

It does not seem to work with find . -name ‘*.dat’ -type f -printf ‘%f\n’ | sort -z | xargs -r0 > output.txt . Is my line wrong due to the printf?

Some versions of sort have a -z option, which allows for null-terminated records.

find folder1 folder2 -name "*.txt" -print0 | sort -z | xargs -r0 myCommand 

Additionally, you could also write a high-level script to do it:

find folder1 folder2 -name "*.txt" -print0 | python -c 'import sys; sys.stdout.write("\0".join(sorted(sys.stdin.read().split("\0"))))' | xargs -r0 myCommand 

Add the -r option to xargs to make sure that myCommand is called with an argument.

Good one (two?). Interestingly, though, the two methods handle . differently. With sort it winds up at the end of the list. with python it sorts to the top. (maybe python sorts with LC_COLLATE=C )

The problem with all these |sort solutions is that you cannot use -exec any longer. OK, although it is possible to rewrite your statement given to -exec so that it works with xargs , the question is, what about «mini-scripts»? ( sh -c . ) I wouldn’t call that trivial to transform a ‘sh -c’ mini-script with multiple commands so that it can work with xargs (if possible at all, that is)

@syntaxerror: What problem do you have using sh -c with xargs? printf %s\\n a b c d e | xargs -n3 sh -c ‘printf %s, «$@»; printf \\n’ x

I think you need the -n flag for sort#

-n, --numeric-sort compare according to string numerical value 

The print0 may have something to do with this, I just tested this. Take the print0 out, you can null terminate the string in sort using the -z flag

Well, that print0 appears to be space-separating the filenames which is what I need to pass to my command, unfortunately

If you have GNU Parallel http://www.gnu.org/software/parallel/ installed you can do this:

find folder1 folder2 -name "*.txt" -print | sort | parallel myCommand 

You can install GNU Parallel simply by:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel chmod 755 parallel cp parallel sem 

I don’t understand that last statement. I create a file with a line break in the file name and execute your command: cd /tmp && touch $’a\nz’ && ls && find -maxdepth 1 -print | sort | parallel echo . Total false output. I know GNU Parallel now, but that answer misses the original question, doesn’t it?

I know that it is bad practice to use crazy characters in file names — I am already including the blank space. I just see that parallel has a -0 parameter. Nice. No downvote. find -maxdepth 1 -print0 | sort -z | parallel -0 echo .

Читайте также:  Какую версию линукс выбрать для дома

@uav In my 25 years of sysadmin I have never seen a user making a file with \n. I have seen plenty of files with ‘ space and «. So unless you have evil users or a filesystem with error, I will reckon you will not meet a file with \n that was not made by a fellow sysadm.

Some implementation of find supports ordered traversal directly via the -s parameter:

-s Cause find to traverse the file hierarchies in lexicographical order, i.e., alphabetical order within each directory. Note: `find -s' and `find | sort' may give different results. 

Some solutions here don’t work correctly because the sort command takes the full «path» string to sorting instead of the filename string.

This is a quite complicated but working example of natural sorting results of the «find» command:

find every_minute -type f -name "*.sh" -printf '%f\t%p\n' | sort -V -k1 | cut -d$'\t' -f2 | tr '\n' '\0' | xargs -r0 -I <> echo 'Found: "<>"' 
Found: "every_minute/api/1_build_synonyms.sh" Found: "every_minute/search_module/2_rotate_index.sh" Found: "every_minute/api/3_check_synonyms.sh" Found: "every_minute/api/4_run_schedule.sh" Found: "every_minute/search_module/10_test.sh" 

Example of an invalid find every_minute -type f -name «*.sh» | sort -z | xargs -r0 echo command result:

every_minute/api/1_build_synonyms.sh every_minute/api/3_check_synonyms.sh every_minute/api/4_run_schedule.sh every_minute/search_module/10_test.sh every_minute/search_module/2_rotate_index.sh 

Источник

How to sort the results of find (including nested directories) alphabetically in bash

I have a list of directories based on the results of running the «find» command in bash. As an example, the result of find are the files:

test/a/file test/b/file test/file test/z/file 
test/file test/a/file test/b/file test/z/file 

4 Answers 4

If you have the GNU version of find, try this:

find test -type f -printf '%h\0%d\0%p\n' | sort -t '\0' -n | awk -F '\0' '' 

To use these file names in a loop, do

find test -type f -printf '%h\0%d\0%p\n' | sort -t '\0' -n | awk -F '\0' '' | while read file; do # use $file done 

The find command prints three things for each file: (1) its directory, (2) its depth in the directory tree, and (3) its full name. By including the depth in the output we can use sort -n to sort test/file above test/a/file . Finally we use awk to strip out the first two columns since they were only used for sorting.

Using \0 as a separator between the three fields allows us to handle file names with spaces and tabs in them (but not newlines, unfortunately).

$ find test -type f test/b/file test/a/file test/file test/z/file $ find test -type f -printf '%h\0%d\0%p\n' | sort -t '\0' -n | awk -F'\0' '' test/file test/a/file test/b/file test/z/file 

If you are unable to modify the find command, then try this convoluted replacement:

find test -type f | while read file; do printf '%s\0%s\0%s\n' "$" "$(tr -dc / ' 

It does the same thing, with $ being used to get a file’s directory name and the tr command being used to count the number of slashes, which is equivalent to a file’s «depth».

(I sure hope there’s an easier answer out there. What you’re asking doesn’t seem that hard, but I am blanking on a simple solution.)

Источник

find command default sorting order

and the output consists of multiple files across multiple sub-folders, what is the default order in which directories are listed? At the same time, what is the sorting order in which files within an individual directory are listed? Sometimes it returns:

./B/01.mp3 ./A/01.mp3 ./A/04.mp3 ./A/02.mp3 

See how first the contents of directory B is listed, then that of directory A. At the same time within directory A, files are listed in a funny order.

Читайте также:  Astra linux common edition virtualbox

From experience it seems to be consistent per install, ie. if you have the same set of files on two machines it will always return one order on one machine, and a completely different one on the other. I have wondered why before, +1

I have an FM transmitter in my car and it always plays songs from my flash card in strange order. I never figured it, but I recognized it was exactly the same order in which the above command returned its output

3 Answers 3

find will be traversing the directory tree in the order items are stored within the directory entries. This will (mostly) be consistent from run to run, on the same machine and will essentially be «file/directory creation order» if there have been no deletes.

However, some file systems will re-order directory entries as part of compaction operations or when the size of the entry needs to be expanded, so there’s always a small chance the «raw» order will change over time. If you want a consistent order, feed the output through an extra sorting stage.

Thanks for your detailed answer! So, if my FM transmitter (see my prev. comment) plays tracks in the order the find command would list them, I’m not able to control in what order I’d like them to be played.

Well, the flash card probably uses a FAT file system and if I remember correctly, manipulating the order of FAT entries is pretty easy with a file system debugger. It may, possibly, be worth copying the songs from the current flash onto a new flash, in the order you want them played, that may be easier.

One of the useful applications of such consistency is a progress estimation of slow find /path/ -exec . with running much faster find /path/ to get sorted list of files first.

One should assume that the order that find emits is the most performant order for the filesystem (native filesystem order without any ordering). Filesystems that keep list of directory entries in binary trees or even more complex structures may result in major changes in the order for miniscule changes to the directory hierarchy. Unfortunately find doesn’t natively support any other ordering because if you pipe the output to e.g. sort , you get zero output until the whole find process is complete because sort must buffer it all for correct order.

You shouldn’t rely on a particular output order from find and instead should use sort and other means to specifically control the order.

I have been working in UNIX/Linux since 1984/1991 respectively and the first command I was taught was find. Linux/GNU has put pretty much everything you need into the current find command so play around with it.

Here are some helpful tips for sorting find output. The -printf option gives you lots of options to enable more complex sorting and file info presentation. It is the best for problems like this. Play with it to see what will work for you. Using -printf you can customize and delimit the results the way you want. This helps quite a bit when you need to post process the results. I hope this helps someone.

  1. If you use -ls and want to sort by file name the 11th field is the file name so you can do the following. The sort -k option can take multiple fields to sort on as well. find /path -ls | sort -k11
  2. If you want finer grain control i.e.sort by date/time in ascending or descending order use the -printf «» option. See the manual for more detail, but the following is an example that will print with fractional seconds so it is very accurate.
Читайте также:  Root any android with linux

EXAMPLE DATE/TIME: 2016-09-17+12:09:57.9013929800

find /path -printf "%T+ %p\n" | sort -n # Ascending find /path -printf "%T+ %p\n" | sort -nr # Descending 

Another way to do this without characters in the date/time string is.

EXAMPLE DATE/TIME: 20160917120013.8101685040

find /path -printf "%AY%Am%Ad%AH%AM%AS %p\n" | sort -n 

Источник

How to find files in subdirs and sort them by filename in a single command?

which means output is sorted based on filename only, but folder information should be maintained as part of the output. Edit: Make example more complicated as the subdirectory structure may include more than one level.

@camh — if possible I would like to use only unix commands. In any case my question is pretty much a duplicate of yours. Can you transfer the best solution to this thread (keep a link to the original anyways) so I can mark is as the solution?

If @Shawn makes the changes I suggested in my comment (use -printf instead of awk ), I think that is the best solution. I’ve reworked my original implementation to use this method.

3 Answers 3

You need to sort by the last field (considering / as a field separator). Unfortunately, I can’t think of a tool that can do this when the number of fields varies (if only sort -k could take negative values).

To get around this, you’ll have to do a decorate-sort-undecorate. That is, take the filename and put it at the beginning followed by a field separator, then do a sort, then remove the first column and field separator.

find . ! -path "./build*" -name "*.txt" |\ awk -vFS=/ -vOFS=/ '< print $NF,$0 >' |\ sort -n -t / |\ cut -f2- -d/ 

That awk command says the field separator FS is set to / ; this affects the way it reads fields. The output field separator OFS is also set to / ; this affects the way it prints records. The next statement says print the last column ( NF is the number of fields in the record, so it also happens to be the index of the last field) as well as the whole record ( $0 is the whole record); it will print them with the OFS between them. Then the list is sort ed, treating / as the field separator — since we have the filename first in the record, it will sort by that. Then the cut prints only fields 2 through the end, again treating / as the field separator.

Источник

Оцените статью
Adblock
detector