4

Suppose I have a string "123456789".

I want to extract the 3rd, 6th, and 8th element. I guess I can use

cut -3, -6, -8

But if this gives

368

Suppose I want to separate them by a white space to get

3 6 8

What should I do?

3
  • 3
    @DigitalTrauma He tried cut. Commented Oct 4, 2013 at 2:04
  • Which shell are you using? echo $SHELL Commented Oct 4, 2013 at 2:04
  • @SmithBlack cut can provide the desired output! Commented Oct 4, 2013 at 5:10

4 Answers 4

2

Actually shell parameter expansion lets you do substring slicing directly, so you could just do:

x='123456789'
echo "${x:3:1}" "${x:6:1}" "${x:8:1}"

Update

To do this over an entire file, read the line in a loop:

while read x; do
  echo "${x:3:1}" "${x:6:1}" "${x:8:1}"
done < file

(By the way, bash slicing is zero-indexed, so if you want the numbers '3', '6' and '8' you'd really want ${x:2:1} ${x:5:1} and {$x:7:1}.)

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your response. Is it possible to generalize this to extracting the 3rd, 6th, and 8th characters for all lines in a file?
Can you try echo "${x:2:1}" "${x:5:1}" "${x:7:1}" instead? In both bashes (Linux and OSX) I've tested, the character counting is 0-based, not 1-based
1

You can use the sed tool and issue this command in your teminal:

sed -r "s/^..(.)..(.).(.).*$/\1 \2 \3/"

Explained RegEx: http://regex101.com/r/fH7zW6


To "generalize" this on a file you can pipe it after a cat like so:

cat file.txt|sed -r "s/^..(.)..(.).(.).*$/\1 \2 \3/"

5 Comments

Thank you for your response. It seems like this part "..(.)..(.).(.)." works when we know the length of the string. If we don't know how many characters in each line (possible very big number), does this still work?
This works when the line has at least 8 characters as it discards anything else after the 8th so yes, it can very big.
No need for a cat. Just redirect the file to sed. sed … < file
Thank you. Just a follow up question. If I want to extract the 999th character, do I need to put 998 "." followed by "(.)" ?
no, put .{998}(.) I used multiple dots (without quantifier) to be simpler, it's equivalent to: /^.{2}(.).{2}(.).(.).*$/
1

Perl one-liner.

perl -lne '@A = split //; print "$A[2] $A[5] $A[7]"' file

Comments

1

Using cut:

$ cat input
1234567890
2345678901
3456789012
4567890123
5678901234
$ cut -b3,6,8 --output-delimiter=" " input
3 6 8
4 7 9
5 8 0
6 9 1
7 0 2

The -b option selects only the specified bytes. The output delimiter can be specified using --output-delimiter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.