Dave
Dave

Reputation: 21

How do I edit a text file to add thousands separators AND left-padding to each line

Re-edited question as requested.

I have a QNAP NAS with a modified Debian OS. The shell is using GNU bash, version 3.2.57(1)-release (x86_64-QNAP-linux-gnu).

I have a program that analyses data and outputs it to a file in a three column format separated by a single space

12000 root 123456

5000 root rootpassword

300 administrator pa$$word

There are hundreds of lines in the file.

I want something to change that file so that the count will have thousand delimiters to be easy to read and be left padded out to 10 characters with spaces. It needs to run in CRON so it can be automated. Thus the above example will be

   12,000 root 123456
    5,000 root rootpassword
      300 administrator pa$$word

I have written a bash script to extract the columns and perform the conversion then simply append the rest on. That works fine but with the delimiters and padding it is 30 lines long and the rest of the script, the main part, is only six. It looks horribly inefficient, takes a very long time and clumsy.

There must be a way to do this more efficiently with sed. Sed looks like it can do it or is there an alternative way with awk or another tool. Those tools are so complex that I have no idea how to do it.

Any ideas on a script that can be submitted via CRON to do this?

Upvotes: 0

Views: 81

Answers (2)

dawg
dawg

Reputation: 103694

If you can use awk it is fairly easy:

LC_ALL=en_US.UTF-8 awk '
{ 
    s=$1
    sub(/^[^ ]+ /,"",$0)
    printf("%'"'"'d %s\n", s, $0) 
}' your_file 

With your example, prints:

12,345 02-01-2024 root reallylongpasswordthatissecure
9,999 01-01-2025 admin anotherreallylongpassword
300 01-01-2025 user 123456

You can also use GNU sed:

gsed -E ':a;s/^([0-9]+)([0-9]{3})\b/\1,\2/;ta' your_file    
#same

You can also add a field width if desired to create a right justified column:

LC_ALL=en_US.UTF-8 awk '
{ 
    s=$1
    sub(/^[^ ]+ /,"",$0)
    printf("%'"'"'10d %s\n", s, $0) 
}' your_file 

12,345 02-01-2024 root reallylongpasswordthatissecure
 9,999 01-01-2025 admin anotherreallylongpassword
   300 01-01-2025 user 123456

Upvotes: 3

markp-fuso
markp-fuso

Reputation: 33749

Assumptions:

  • we only want to convert the first space-delimited field
  • the first field will always be an integer (eg, we do not have to worry about floats or numbers that already have a thousands separator applied)
  • we are to left pad the new number with spaces for a total length of 10 characters (including the separator(s)); this also means the integer will be no more than 8 digits (otherwise we'll end up with an output that's more than 10 characters in length)
  • we are not to modify the password field (as displayed in OP's various sets of output)

One bash idea using a while/read loop and a printf call:

while read -r fld1 rest_of_line
do
    LC_ALL=en_US.UTF-8 printf "%'10d %s\n" "${fld1}" "${rest_of_line}"
done < file.txt

NOTES:

  • whether or not you need the LC_ALL=en_US.UTF-8 depends on your default character set
  • if you're using a different character set that provides the thousands separator then feel free to replace en_US.UTF-8 as needed

This generates:

    12,345 02-01-2024 root reallylongpasswordthatissecure
     9,999 01-01-2025 admin anotherreallylongpassword
       300 01-01-2025 user 123456

Upvotes: 2

Related Questions