0

I process a text file with many domain like

abcd.efgh.ijkl.mnop

I hope to add a 3 at the same line no matter how it is at the beginning or at the end.

current I use

sed 's/[^.]//g' thetextfile | awk '{ print length }' > thenumber

then I use librecalc to combine them.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 1
    Welcome to Stack Overflow! Questions seeking code help must include the shortest code necessary to reproduce it in the question itself preferably in a [Stack Snippet](https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/?more_on=xron.net). See How to create a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). It also very helpful to show in your Question an expected result, and quote any (exact) errors you are getting. You are expected to show any research you have put into solving this question yourself. – Ron Dec 28 '21 at 06:17
  • 1
    Show example input, and show expected output... – Ron Dec 28 '21 at 06:18

3 Answers3

2

In plain bash, without using any external utility:

#!/bin/bash

while read -r line; do
    dots=${line//[^.]}
    printf '%d\t%s\n' ${#dots} "$line" 
done < file
M. Nejat Aydin
  • 9,597
  • 1
  • 7
  • 17
  • 1
    `while read` is very inefficient, though; this is exactly the type of situation where you should use a tool like `sed` or Awk instead. – tripleee Dec 28 '21 at 09:44
  • @tripleee Agreed. `awk` is blindingly fast compared to pure `bash` for this kind of tasks. – M. Nejat Aydin Dec 28 '21 at 10:19
1

Using a perl one-liner, taking advantage of tr returning the number of changes:

$ perl -ne 'print tr/././, " ", $_' input.txt
3 abcd.efgh.ijkl.mnop
6 abcd.efgh.ijkl.mnop...
4 abcd.efgh.ijkl.mnop.
Shawn
  • 47,241
  • 3
  • 26
  • 60
1

The blindingly obvious answer is

awk -F . '{ print NF-1, $0 }' thetextfile >thenumber

Combining the results to a single file in an external utility seems like a humongous overcomplication; just process all the files in one go.

awk -F . '{ print NF-1, $0 }' * >allnumbers

or if your needs are more complex maybe something like

for file in *.txt; do
    echo "$0: processing $file ..." >&2
    awk -F . '{ print NF-1, $0 }' "$file"
done >allnumbers

The -F . says to use the literal dot as field separator, and NF is the number of fields (which will be one more than the number of separators; look up "fencepost error" if you don't understand why).

In more complex cases still, maybe append the output from each file with >>allnumbers inside the loop if you really need to (but understand that this is less efficient than only writing once after the done).

Awk's default output field separator is a single space; if you want to produce TSV (tab-separated output) or CSV, you can set OFS="\t" or OFS="," as required.

tripleee
  • 175,061
  • 34
  • 275
  • 318