112

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:

Community
  • 1
  • 1
Binny V A
  • 2,036
  • 3
  • 20
  • 23
  • 5
    Not really a duplicate. [Extract substring in Bash](https://stackoverflow.com/q/428109) 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. – Adrian W Oct 24 '18 at 10:34

6 Answers6

204

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.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Toybuilder
  • 11,153
  • 5
  • 28
  • 33
  • 2
    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. – Toybuilder Nov 14 '11 at 17:44
  • 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?" – user1731553 Apr 05 '16 at 05:46
  • 1
    `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". – ArtOfWarfare Sep 11 '17 at 14:31
  • Consider to indicate quickly: what does `-c` do? – Manuel Jordan Dec 20 '21 at 13:51
  • @ArtOfWarfare huge thanks for your comment - it explains the following answer: https://stackoverflow.com/a/428118/3665178 – Manuel Jordan Dec 20 '21 at 13:52
104

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.

dmckee --- ex-moderator kitten
  • 98,632
  • 24
  • 142
  • 234
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.

ata
  • 2,045
  • 1
  • 14
  • 19
  • Just remember, that 'indexed substring expansion' is not part of the [POSIX standard](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06). 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. – JepZ Dec 31 '18 at 10:59
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

Juanma
  • 3,961
  • 3
  • 27
  • 26
16
${string:position:length}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
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).

fiatjaf
  • 11,479
  • 5
  • 56
  • 72
camh
  • 40,988
  • 13
  • 62
  • 70