251

How can I remove all text after a character, in this case a colon (":"), in bash? Can I remove the colon, too? I have no idea how to.

7 Answers 7

426

In Bash (and ksh, zsh, dash, etc.), you can use parameter expansion with % which will remove characters from the end of the string or # which will remove characters from the beginning of the string. If you use a single one of those characters, the smallest matching string will be removed. If you double the character, the longest will be removed.

$ a='hello:world'

$ b=${a%:*}
$ echo "$b"
hello

$ a='hello:world:of:tomorrow'

$ echo "${a%:*}"
hello:world:of

$ echo "${a%%:*}"
hello

$ echo "${a#*:}"
world:of:tomorrow

$ echo "${a##*:}"
tomorrow
16
  • 16
    This is native shell string manipulation, so no additional processes will be spawned. Reference Bash Parameter Substitution, Bash String Manipulation and Better Bash Scripting Commented Apr 14, 2014 at 3:13
  • @denniswilliamson How could I deleted 2 characters after a specific string like hello:world will become hello:wo by using ${a%:*}?
    – 3kstc
    Commented Jun 25, 2016 at 13:05
  • 1
    Great answer, thanks a lot, but it will be nice to also add "${a##*:}" for getting only tomorrow =)
    – avtomaton
    Commented Nov 28, 2016 at 1:40
  • 1
    @openCivilisation: You probably need to use regular expression matching then: a='hello:world:of:tomorrow'; pattern=''^([^:]*:).*$'; [[ $a =~ $pattern ]]; echo "${BASH_REMATCH[1]}"`. That matches only if there is a colon. If you want that to be optional, a different pattern would have to be used. An explanation of Bash regexes (and regexes in general) is beyond the scope of these comments. You can find other questions that discuss this or post your own. Commented Mar 10, 2019 at 16:41
  • 1
    @kp123: It's the first example in my answer. The second time I show it (where "tomorrow" is removed), it's almost exactly the situation you're asking about. Commented Aug 28, 2019 at 21:29
223

An example might have been useful, but if I understood you correctly, this would work:

echo "Hello: world" | cut -f1 -d":"

This will convert Hello: world into Hello.

6
  • 6
    cut works, but I Dennis' answer is better and more flexible. Does anyone know if it spawns a new process like cut?
    – JoBu1324
    Commented Feb 20, 2014 at 18:06
  • 4
    It's better to use Bash's built-in parameter expansion features than generating subshells running tools like basename and cut, see Dennis's answer below Commented Jun 14, 2016 at 17:32
  • 2
    cut can read from stdin, so it is better especially when you have a very long string that you need to process, like the contents of a file.
    – Sahas
    Commented Apr 26, 2017 at 8:34
  • 2
    And how would this be applied to hello: world. This is half an answer.
    – basickarl
    Commented Oct 9, 2017 at 12:20
  • It can be done using subsitution syntax also like {var/:/''}, but works only in bash..
    – Mahesh
    Commented Feb 14, 2019 at 11:40
23
$ echo 'hello:world:again' |sed 's/:.*//'
hello
2
15

I know some solutions:

# Our mock data:
A=user:mail:password
  1. With awk and pipe:
$ echo $A | awk -v FS=':' '{print $1}'
user
  1. Via bash variables:
$ echo ${A%%:*}
user
  1. With pipe and sed:
$ echo $A | sed 's#:.*##g'
user
  1. With pipe and grep:
$ echo $A | egrep -o '^[^:]+'
user
  1. With pipe and cut:
$ echo $A | cut -f1 -d\: 
user
1
  • 1
    I like: echo $A | cut -f1 -d\: Easy to read!
    – dave
    Commented Apr 15, 2022 at 3:50
7
egrep -o '^[^:]*:'
2
  • 1
    can you explain how to interpret this , Thank you.
    – Raja G
    Commented Dec 28, 2016 at 6:46
  • 3
    egrep is grep with -E. It makes no difference here from regular grep. -o instructs grep to print out only the part of the line that matches the expression. ^ anchors the match to the start of a line. [^:]* matches zero or more characters that are not the : character. : matches the character :.
    – cdhowie
    Commented Dec 29, 2016 at 16:16
4

trim off everything after the last instance of ":"

grep -o '^.*:' fileListingPathsAndFiles.txt

and if you wanted to drop that last ":"

grep -o '^.*:' file.txt | sed 's/:$//'

@kp123: you'd want to replace : with / (where the sed colon should be \/)

1
  • 1
    The only correct answer. As this answer removes after a specific character given, the other answers remove the character aswell.
    – basickarl
    Commented Jun 16, 2021 at 15:50
3

Let's say you have a path with a file in this format:

/dirA/dirB/dirC/filename.file

Now you only want the path which includes four "/". Type

$ echo "/dirA/dirB/dirC/filename.file" | cut -f1-4 -d"/"

and your output will be

/dirA/dirB/dirC

The advantage of using cut is that you can also cut out the uppest directory as well as the file (in this example), so if you type

$ echo "/dirA/dirB/dirC/filename.file" | cut -f1-3 -d"/"

your output would be

/dirA/dirB

Though you can do the same from the other side of the string, it would not make that much sense in this case as typing

$ echo "/dirA/dirB/dirC/filename.file" | cut -f2-4 -d"/"

results in

dirA/dirB/dirC

In some other cases the last case might also be helpful. Mind that there is no "/" at the beginning of the last output.

3
  • 2
    What if you have a directory "/resources/views/admin/users/relationships/posts.blade.php" and you want to truncate everything after the LAST occurrence of the "/", given that you do NOT know how many "/" characters are in the string. So here I would want the output to be "/resources/views/admin/users/relationships/" (or even /resources/views/admin/users/relationships without the trailing slash). How would you do that?
    – kp123
    Commented Aug 28, 2019 at 21:21
  • 1
    more than a year old; There's a command for that: dirname
    – Michiel
    Commented Aug 12, 2020 at 11:45
  • What about if i have a number 19359.364263397103 how do i remove all chars starting with . and all tothe right so all thats left is the left part whats the command look like for that?
    – Jay Mee
    Commented Oct 3, 2022 at 16:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.