How to truncate a string to x number characters?

Hello:

I have a large file which contains lines like the following:

1/t123ab, &Xx:1:1234:12345:123456@ABCDEFG... at -$100.00%

/t is a tab, spaces are as indicated
the string "&Xx:1:1234:12345:123456$ABCDEFG..." has a slightly variable number of numbers and letters, but it always starts with "&Xx" and includes 4 ":"
I want to truncate that string to 20 characters plus "..." at the end.

So basically, I would like to do the following

sed 's/&Xx[any_number_of_characters]\.\.\./&Xx[17_characters]\.\.\./'

leaving all the rest untouched.
However

sed 's/&Xx.+\.\.\./test\.\.\./' did not make any changes

sed 's/&Xx........../test/' does change part of the string into "test", so the "." is recognized as representing "any character but new line"
sed 's/&Xx.{10}/test/' does not alter the file

I am using Linux Mint version 12

are there other ways to achieve this truncation? (awk?)

Thanks in advance.

Assumptions:
1) no more than 1 occurrence of the mentioned string (the one starting with &Xx ) in a line,
2) no . character between the starting &Xx and ending ... in the string.

a='1	123ab, &Xx:1:1234:12345:123456@ABCDEFG... at -$100.00%'

echo "$a"|awk 'match($0,/&Xx[^.]*[.]{3}/){
if(RLENGTH>23)
 $0=substr($0,1,RSTART-1) substr($0,RSTART,20) substr($0,RSTART+RLENGTH-3)
}1'

1       123ab, &Xx:1:1234:12345:123... at -$100.00%
perl -lne '{ s/(&Xx:.*)\.{3}/substr($1,0,20)."..."/ge;print ;}' 

This will avoid unnecessary substitutions:

perl -lne '/&Xx/ && do { s/(&Xx:.*?)\.{3}/substr($1,0,20)."..."/ge;print ;}'

The assumption is correct: there are no "." characters in the string except the three at the very end and there s only one occurrence of the string in a line.

There are however also lines that do not contain such a string.

Neither the awk command nor the perl -lne did truncate the string on my computer.

I have no clue why, as the output from elixir_sinari indicates that awk would do the job.

perl -lne '/&Xx/ && do { s/(&Xx:.*?)\.{3}/substr($1,0,20)."..."/ge;print ;}'

eliminated all lines that did not contain the string - which was not an intended outcome, but left the string untouched

@Tectone :
Yes please use my updated code with elixirs modification !

Anyways please take a look below..

$ perl -lne '{ s/(&Xx:.*?)\.{3}/substr($1,0,20)."..."/ge;print ;}' input_file
1       123ab, &Xx:1:1234:12345:123... at -$100.00%
somestring
newstring

Thats working fine for me !

Try this...

awk '{match($0,"([0-9]+.*&Xx)(.*)",a);print a[1],substr(a[2],0,17)"..."}' infile

If solaris, use nawk

--ahamed

[root@host dir]# cat file
helloworld
1       123ab, &Xx:1:1234:12345:123456@ABCDEFG... at -$100.00%
somestring
newstring
[root@host dir]# sed 's/\(&Xx.\{17\}\)[^.]*/\1/g' file
helloworld
1       123ab, &Xx:1:1234:12345:123... at -$100.00%
somestring
newstring
[root@host dir]#

Thanks... this seems to be working well.
I do not understand the sed syntax though. Maybe you can explain so that I can learn .. and maybe others too. E.g. the use of "\1" to represent the substitute string. What is the meaning of the ".\" after "&Xx". the {17} represents the 17 characters after "&Xx"... but what is the "\" doing after "17". I assume the last part [^.]* means any number of characters but not "."

Thanks in advance

\1 refers to the first pattern matched in round braces. In this case, \(&Xx.\{17\}\) . Sed expects the round braces to be escaped - \( and \)

Different regex engines process patterns differently. For e.g., to match any character exactly 17 times in perl, you would simply say .{17}
In sed, you would have to say .\{17\} by escaping the curly braces.

Your assumption is correct about [^.]* . Going by the books, this is known as non-greedy pattern matching.