Sort a las file keep the header as it is

I have several las files with a header and each file start Version and text and before the data starts end up with ~Ascii, then the numbers starts:
-------------------------------------------------------------------------

~Version
.....text....
~Ascii
2  abc  230   1 name
1  abc  400   1 name2
3  abb  350   2  name

----------------------------------------------------------------------------
What I want to do is to keep the header as it is and sort with the first column
the result to look something as following :

~Version
.....text....
~Ascii
1  abc  400   1 name2
2  abc  230   1 name
3  abb  350   2  name

and if it is possible to run for all files in one go, since all the files are *.las file?

thank
T

Operating inline of the file? Hard.

If you can tolerate a stream of output from processing the file twice, then ok. I'm assuming only one ~Ascii in the file.

sed -n '1,/^~Ascii/p' <test.las; sed  '1,/^~Ascii/d' <test.las | sort -k1,1n

If you are saying that you want to sort all of the *.las files together into a single output file keeping the header from the 1st file and throwing away the other headers, you could try:

sed -n '1,/~Ascii/p;/~Ascii/q' *.las;sed '/~Version/,/~Ascii/d' *.las|sort -k1,1n

Thanks Don/cjcox

I want to sort each file and the output should be new file for each file.
When I tried the one you post. It doesnot give me output file. And
each new file should keep the header and the data sorted.

Assuming you want to sort the files in place and you don't have any hard links or non-default file modes or group-IDs you need to preserve in your .las files, a simple loop of the cjcox's suggestion should do what you want:

for file in *.las
do	sed -n '1,/~Ascii/p;/~Ascii/q' "$file" > "$file.$$" && \
	sed '1,/~Ascii/d' "$file" | sort -k1,1n >> "$file.$$" && \
	mv "$file.$$" "$file" || rm -f "$file.$$"
done

If you want new files created instead of replacing the original files, try:

for file in *.las
do	sed -n '1,/~Ascii/p;/~Ascii/q' "$file" > "$file.new"
	sed '1,/~Ascii/d' "$file" | sort -k1,1n >> "$file.new"
done

More efficient with awk:

for file in *.las
do
  awk '(sort==1) {print | "sort -k1,1n"; next} ($1~/^~Version/) {sort=1} {print}' "$file" > "$file.$$" &&
  cp "$file.$$" "$file" &&
  rm -f "$file.$$"
done

Would be even shorter with perl, thanks to its -i option and internal sort.

I'd have to do some benchmarking to see if sed , sed | sort is slower than using awk to invoke sh to invoke sort ; since there are three fork() and exec family (or spawn() ) calls either way; but I like the concept.

But, shouldn't:

($1~/^~Version/) {sort=1}

be:

($1~/^~Ascii/) {sort=1}

in your script?

Yes, my mistake. Of course sorting must start after the ~Ascii !

Thanks a lot Don
It worked with the creating new file.
_________________________________________________

for file in *.las
do      sed -n '1,/~Ascii/p;/~Ascii/q' "$file" > "$file.new"
        sed '1,/~Ascii/d' "$file" | sort -k1,1n >> "$file.new"
done

__________________________________________________

I have additional question to the las file.
Now it is sorted, there is a small issue with the file.
The first column is depth .

11200.45 abc 400 1 name2
11204     abc 230 1 name
11204     abb 350 2 name
11500     abc 400 1 name2
11632     .... ..... .  .........
11632   .....
11900

and so on

Once the file is sorted I am not able to load it to the software I am using .
The reason is that there is a repetition of depth in between (11204 ,11204)
What I want to do is if it find a repetition to add to one of the depth ".1"
the file will look something as following :

11200.45  abc 400 1 name2
11204      abc 230 1 name
11204.1    abb 350 2 name
11500      abc 400 1 name2
11632       .... ..... .  .........
11632.1    .....
11900

and so on

Thanks and regards

How many lines could appear in your input with the same 1st column value. (I assume we need to do something like 11200.01 , 11200.02 , ... 11200.45 rather than 11200.1 , 11200.2 , ... 11200.45 so the program reading your data won't see 11200.1 and 11200.10 as having the same numeric value??? So, the question is how many digits do you need to put after the decimal point to make the number of digits after the decimal constant for the lines that have the same base first field value?

Thanks again Don

The repetition happens once for each and some times twice.
Two digits after the decimal would do.

11200.45 abc 400 1 name2
11204     abc 230 1 name
11204     abb 350 2 name
11500     abc 400 1 name2
11600     ...  .............
11632     .... ..... .  .........
11632   .....
11632   ...
11900
12000

regards

I don't get it... If a number can be repeated in the input no more than three times, why isn't one digit enough?

If a number can be repeated in the input no more than three times, where did 11200.45 come from? Is the above supposed to be input or output? If it is input why are there any decimal points in the 1st field in the input? If it is output, why aren't there decimal points after two of the lines that start with 11632 ?

Are you now saying that the input could have three lines with 11200.45 in the first column and you want the output to be 11200.45 , 11200.45.1 , and 11200.45.2 ? Do you want the output sorted numerically or alphanumerically? (A numeric sort might not work if the strings you're sorting contain more than one decimal point.

Hi
It is enough with one digit decimal. but in some of the files , there is two digit decimal for e.g. in one of the file the first is 11200.45 then the others in the first column is no decimal or in between there is a decimal.. if the file is as following :
the "." is for decimal ...

11200.45 abc 400 1 name2
11204     abc 230 1 name
11204     abb 350 2 name
11500     abc 400 1 name2
11600     ...  .............
11632     .... ..... .  .........
11632   .....
11632   ...
11900
12000

The result I am looking for is :

11200.45 abc 400 1 name2
11204     abc 230 1 name
11204.1     abb 350 2 name
11500     abc 400 1 name2
11600     ...  .............
11632     .... ..... .  .........
11632.1   .....
11632.2   ...
11900
12000

or

11200.45 abc 400 1 name2
11204     abc 230 1 name
11204.01     abb 350 2 name
11500     abc 400 1 name2
11600     ...  .............
11632.01     .... ..... .  .........
11632 .02  .....
11632   ...
11900
12000

regards

I do not yet understand how the input you are processing is supposed to be converted into the output you want. Explain what output should be produced by showing us (in CODE tags) the exact output that should be produced for the following input AND by stating the rules (in English) that explain the logic your script is supposed to use to determine why that is the output it should produced from that given input:

11200.45 abc 400 1 name2 original
11200.45 abc 400 1 name2 update 1
11200.45 abc 400 1 name2 update 2
11204     abc 230 1 name
11204     abc 230 1 name
11204     abc 230 1 name
11204.01     abc 230 1 name
11204.01     abc 230 1 name
11204.01     abc 230 1 name
11204.02     abc 230 1 name
11204.02     abc 230 1 name
11204.02     abc 230 1 name
11204.1     abb 350 2 name
11204.1     abb 350 2 name
11204.10     abc 230 1 name
11204.10     abc 230 1 name
11500     abc 400 1 name2
11600     ...  .............
11632     .... ..... .  ......... original
11632     .... ..... .  ......... update 1
11632     .... ..... .  ......... update 2
11632.01     .... ..... .  ......... original
11632.01    .... ..... .  ......... update 1
11632.01     .... ..... .  ......... update 2
11632 02    .... ..... .  ......... original
11632.02     .... ..... .  ......... update 1
11632.02     .... ..... .  ......... update 2
11632.1   ..... original
11632.1   ..... update 1
11632.11 .... original
11632.11 .... update 1
11632.2   ... original
11900
12000

The script I am looking for is :

If In first column repeats
then the column value + .1, else column.

I have attached two files :
Orginal_las.txt :is the original file unsorted and with some repeating values in column 1.
result_las.txt : is the the result I am looking for, sorted and no repeating values in column 1.

regards

for file in *.las
do
  { # reading from file
    # header
    while read line
    do
      echo "$line"
      case $line in "~Ascii"*) break;; esac
    done
    # sort the rest and add number suffix for duplicates
    sort -k1,1n |
    awk '{if ($1==p1) {sub("  ","."++c)} else {c=0; p1=$1} print}'
  } < "$file" > "$file.new"
done

Thanks Don and MadeInGermany

Know it is working .

regards

I'm glad that what MadeInGermany suggested is working for you. But, of course, if the 1st line in the sample input you provided in post #9 in this thread:

11200.45 abc 400 1 name2
11204     abc 230 1 name
11204     abb 350 2 name
11500     abc 400 1 name2
11632     .... ..... .  .........
11632   .....
11900

had another entry with the same decimal value (or if any two lines in your input contained the same value including a decimal point), it just won't work. First the code would try to replace the first two spaces in the on the 2nd matching line with .1 creating (if there were to spaces in that line) 11200.45.1 (which is not a valid decimal number). And, second, if the input can contain decimal values in the 1st column, there is nothing in MadeInGermany's code to detect duplicates created as a result of adding the .1 to the ends of a duplicated line that didn't contain a decimal point.