2

I have a bunch of folders which are labelled in this way:

 conf1
 conf2
 ...

But the order in the home directory is like

 conf1
 conf10
 conf100
 conf101
 ...
 conf2
 conf20
 conf200
 conf201
 ...

Because each folder contains a file named "distance.txt", I would like to be able to print the content of the distance.txt file, from each single folder, but in order, going from folder 1-->2-->3... to the final folder 272.

I tried several attempts, but every time the final file contains the all set of values in the wrong order; this is the piece of code I set:

   ls -v | for d in ./*/; 
     do (cd "$d" && cat distance.txt >> /path/to/folder/d.txt
         );
     done

As you can see I tried to "order" the folders with the command

ls -v

and then to couple the cycle to iteratively save each file.

Can you kindly help me?

3
  • for d in $(ls -vd conf*); do echo "$d"; done?
    – Cyrus
    Mar 12, 2017 at 17:00
  • Hi! Thanks! I didn't know there was the possibility to "merge" the command ls in a for loop. Really useful! Thanks a lot!
    – Tommy
    Mar 12, 2017 at 17:14
  • I would point out that this approach causes problems when filenames contain spaces, tabs or line breaks. In general, it is not recommended to parse the output of ls command.
    – Cyrus
    Mar 12, 2017 at 17:21

6 Answers 6

5

For such a relatively small set of folders you could use a numerical loop

for n in {1..272}
do
    d="conf$n"
    test-d "$d" && cat "$d/distance.txt" >> /path/to/folder/d.txt
done
2
4

If you have a sort that supports null delimiters and version sorting, you could safely do

printf '%s\0' conf*/ | sort -zV | while read -rd '' d; do 
  whatever with "$d"
done

I think. If you have zsh it's much easier since it supports a numeric glob qualifier

for d in conf*(/n); do
  whatever with "$d"
done
1
  • Ok, thanks a lot Steeldriver, I will take into account your hints! Thanks a lot!
    – Tommy
    Mar 12, 2017 at 17:13
0
printf '%s\n' conf{1..101} conf{2..272} |
xargs sh -c 'shift "$1"; printf "%s/distance.txt\n" "$@"' 2 1 > /path/to/folder.txt

Or,

printf '%s\n' conf{1..101}/distance.txt conf{2..272}/distance.txt |
xargs cat > /path/to/folder.txt
1
  • Ok, thanks a lot Rakesh, I will take into consideration your suggestion! Thanks again!
    – Tommy
    Mar 12, 2017 at 17:13
0
printf 'conf%s/distance.txt\n' {1..272} | xargs cat >/path/to/folder/d.txt 2>/dev/null

Here we make use of the fact that if the dir. confNNN/ &/or distance.txt do not exist, a warning will be generated which we ignore. The real output happens only in case the dir+file exists, hence no need for testing file & dir. existence. cat to the rescue.

Also there is no appending >> required, as the xargs even if it invokes cat multiple times, it still dumps the output in one bunch into the log.

So it's one place which is not a UUOC ;-)

0

Create a tiny perlscript to sort the arguments passed by the shell:

#!/usr/bin/perl -l -s

$re ||= qr/(\d+)/;

sub bynum {
   ($aa) = $a =~ $re;
   ($bb) = $b =~ $re;
   return $aa <=> $bb;
}

map { print } sort bynum @ARGV;

Save the script as sortargsbynum and call it as shell expression:

for d in $(sortargsbynum conf*); do
   cat $d/distance.txt >> /path/to/folder/d.txt
done

You can pass a special regular expression for matching, for example to only match a number at end of the name:

for d in $(sortargsbynum -re='(\d+)$' *conf*); do
   echo $d
done

conf1
conf2
conf10
conf20
conf99
1stconf100
2ndconf100
conf101
conf200
conf201
0

You can sort first by length of string, then lexicographically if everything shares a common prefix. If two numbers share the same number of digits, then lexicographic and numerical comparison result in the same order.

 ls -1 | awk '{print $1 " " length($1)}' | sort -n -k2,2 -k1,1 | awk '{print $1}'

You can also use perl to collect the names of the folders and then extract the trailing numerical suffix. Then you can sort numerically based on this suffix.

ls -1 | perl -e '@lines = <STDIN>; @lines = sort { $a =~ /(\d+)$/; $aa = $1; $b =~ /(\d+)$/; $aa <=> $1;  } @lines; print foreach @lines;'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .