116

I want to find a linux command that can return a part of the string. In most programming languages, it's the substr() function. Does bash have any command that can be used for this purpose. I want to be able to do something like this... substr "abcdefg" 2 3 - prints cde.


Subsequent similar question:

1
  • 5
    Not really a duplicate. Extract substring in Bash asks for cutting out a sequence of characters surrounded by a certain delimiter. This question asks for cutting out a piece of a string giving numerical values for offset and length like substr() does. This is not the same. Commented Oct 24, 2018 at 10:34

6 Answers 6

211

If you are looking for a shell utility to do something like that, you can use the cut command.

To take your example, try:

echo "abcdefg" | cut -c3-5

which yields

cde

Where -cN-M tells the cut command to return columns N to M, inclusive.

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

5 Comments

Even though I have the "accepted" answer, I would like to point out that if you want to do a lot of sub-string extraction, using the built-in substring expansion (see dmckee's answer) is the more efficient way to go. That said, cut is easier to remember and use.
what do we need to do if we want to start from 3rd char till end of the string ie: "abcdef" we need cdef then echo "abcdef" | cut -c3?"
cut has some useful arguments you can use. -f changes it from counting characters to counting fields, delimited by TAB by default or by any character you specify following -d. So to get your input string up until but not including the first slash (exactly what I wanted), you can do: cut -d/ -f-1, which can be read as "cut on substrings delimited by /, only return the first one".
Consider to indicate quickly: what does -c do?
@ArtOfWarfare huge thanks for your comment - it explains the following answer: stackoverflow.com/a/428118/3665178
105

From the bash manpage:

${parameter:offset}
${parameter:offset:length}
        Substring  Expansion.   Expands  to  up  to length characters of
        parameter starting at the character  specified  by  offset.
[...]

Or, if you are not sure of having bash, consider using cut.

9 Comments

interesting, I did not know about this. For more flexibile substring options: man cut
Shell extensions are nice, but... meh.
I mostly agree. I usually write shell scripts in vanilla /bin/sh. But I find that I have to know some bashisms to read shell scripts...
Is there something like ${str:3:-3} to extract a substring from char 3 to last char minus -3?
Oh, but echo ${str:2:-2} does what I want.
|
35

In "pure" bash you have many tools for (sub)string manipulation, mainly, but not exclusively in parameter expansion :

${parameter//substring/replacement}
${parameter##remove_matching_prefix}
${parameter%%remove_matching_suffix}

Indexed substring expansion (special behaviours with negative offsets, and, in newer Bashes, negative lengths):

${parameter:offset}
${parameter:offset:length}
${parameter:offset:length}

And of course, the much useful expansions that operate on whether the parameter is null:

${parameter:+use this if param is NOT null}
${parameter:-use this if param is null}
${parameter:=use this and assign to param if param is null}
${parameter:?show this error if param is null}

They have more tweakable behaviours than those listed, and as I said, there are other ways to manipulate strings (a common one being $(command substitution) combined with sed or any other external filter). But, they are so easily found by typing man bash that I don't feel it merits to further extend this post.

1 Comment

Just remember, that 'indexed substring expansion' is not part of the POSIX standard. So while it is probably faster on bash than the alternatives, it might get in your way when you want to run your script on different operating systems.
24

In bash you can try this:

stringZ=abcABC123ABCabc
#       0123456789.....
#       0-based indexing.

echo ${stringZ:0:2} # prints ab

More samples in The Linux Documentation Project

2 Comments

Is there a syntax to replace the number 2 with infinity ?
@ToiletGuy Yes, just discard it. echo ${stringZ:9} prints ABCabc
16
${string:position:length}

3 Comments

As usual, sitting down here with no upvotes, WTF. This worked so well for me in my parse_git_branch command. Naice!
Can the length become the infinity ?
@DanRosenstark while this answer is helpful it's just a code snippet with no explanation (regardless of how trivial it may be). This is a poor answer in the realm of SO rules.
15

expr(1) has a substr subcommand:

expr substr <string> <start-index> <length>

This may be useful if you don't have bash (perhaps embedded Linux) and you don't want the extra "echo" process you need to use cut(1).

1 Comment

Heredocs work without bash (<<EOF, your contents, then EOF), and typically (on systems where TMPDIR in on tmpfs/shmfs/etc) cost less than the subshell to run echo would.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.