135

I have a string like that:

|abcdefg| 

And I want to get a new string called in someway (like string2) with the original string without the two | characters at the start and at the end of it so that I will have this:

abcdefg 

Is that possible in bash?

10 Answers 10

151

You can do

string="|abcdefg|" string2=${string#"|"} string2=${string2%"|"} echo $string2 

Or if your string length is constant, you can do

string="|abcdefg|" string2=${string:1:7} echo $string2 

Also, this should work

echo "|abcdefg|" | cut -d "|" -f 2 

Also this

echo "|abcdefg|" | sed 's/^|\(.*\)|$/\1/' 
5
  • 2
    and also awk -F\| '{ print $2 }' <<<"|string|" Commented Dec 23, 2011 at 17:45
  • 1
    @enzotib You always have cool awk solutions. I need to learn awk. Commented Dec 23, 2011 at 18:36
  • 3
    and also IFS='|' read string2 <<< $string :) Commented Dec 23, 2011 at 20:38
  • 21
    and also, in bash 4.2 and newer, "${string:1:-1}" Commented Jul 5, 2012 at 12:52
  • Read under the "parameter expansion" section in man bash. Commented Sep 5, 2012 at 20:44
82

Here's a solution that is independent of the length of the string (bash):

string="|abcdefg|" echo "${string:1:${#string}-2}" 
67

Going off a few posts listed here it seems the simplest way to do it is:

string="|abcdefg|" echo ${string:1:-1} 

edit: works on ubuntu with bash 4.2; does not work on centOS with bash 4.1

2
  • 3
    This should be have been the top answer. You won't find any bash 4.1 on modern systems. :) Commented Jul 9, 2020 at 14:17
  • The first 1 in this answer represents how many characters are dropped from the start, The second 1 represents how many characters are dropped from the end. So echo echo ${string:2:-3} would yield output:bcde. Commented Feb 19, 2021 at 17:48
34

Another way is to use head & tail commands:

$ echo -n "|abcdefg|" | tail -c +2 | head -c -2 abcdefg 
4
  • 1
    I had a string of [something something] with a goal to cut brackets, so echo "[something something]" | tail -c +2 | head -c -2 worked out. Thanks for a tip! Commented Dec 13, 2015 at 15:36
  • 2
    Obviously, it should be echo -n "|abcdefg|" | tail -c +2 | head -c -1. I'm not sure why my edits were rejected... It's very sad, to be honest. See man head for more info Commented Mar 27, 2019 at 13:11
  • Best answer, does what was requested with the most simple tools and is not dependent on extra factors like char is x, y or z. Commented Jan 17, 2023 at 13:13
  • 1
    Not working on the latest shell editions (at least on mac...). I get head: illegal byte count -- -2 Commented Sep 7, 2023 at 10:03
11

You can also use sed to remove the | not just referencing the symbol itself but using positional references as in:

$ echo "|abcdefg|" | sed 's:^.\(.*\).$:\1:' abcdefg 

Where ':' are the delimiters (you can replace them with / or any character not in the query, any sign following the s will do it) Here ^ (caret) means at the beginning of the input string and $ (dollar) means at the end. The . (point) that it's after the caret and the one that it's before the dollar sign represents a single character. So in other words we are deleting the first and last characters. Take in mind this will delete any characters even if | it's not present in the string.

EX:

$ echo "abcdefg" | sed 's:^.\(.*\).$:\1:' bcdef 
10

And another one:

string="|abcdefg|" echo "${string//|/}" 
3

shell function

A bit more verbose approach, but works on any sort of first and last character, doesn't have to be the same. Basic idea is that we are taking a variable, reading it character by character, and appending only those we want to a new variable

Here's that whole idea formatted into a nice function

crop_string_ends() { STR="$1" NEWSTR="" COUNT=0 while read -n 1 CHAR do COUNT=$(($COUNT+1)) if [ $COUNT -eq 1 ] || [ $COUNT -eq ${#STR} ] then continue fi NEWSTR="$NEWSTR"$CHAR done <<<"$STR" echo $NEWSTR } 

And here is that same function in action:

$> crop_string_ends "|abcdefg|" abcdefg $> crop_string_ends "HelloWorld" elloWorl 

Python

>>> mystring="|abcdefg|" >>> print(mystring[1:-1]) abcdefg 

or on command line:

$ python -c 'import sys;print sys.stdin.read()[1:-2]' <<< "|abcdefg|" abcdefg 

AWK

$ echo "|abcdefg|" | awk '{print substr($0,2,length($0)-2)}' abcdefg 

Ruby

$ ruby -ne 'print $_.split("|")[1]' <<< "|abcdefg|" abcdefg 
2

Small and universal solution:

expr "|abcdef|" : '.\(.*\).' 

Special in this case and allowing that the '|' character may be there or not:

expr "|abcdef" : '|*\([^|]*\)|*' 
2
$ string="|abcdefg|" $ string="${string#?}" && string="${string%%?}" $ echo "$string" abcdefg 

From http://tldp.org/LDP/abs/html/parameter-substitution.html

${var#Pattern}
Remove from $var the shortest part of $Pattern that matches the front end of $var.
${var%%Pattern}
Remove from $var the longest part of $Pattern that matches the back end of $var.

2

You can use this:

echo "|abcdefg|" | tr -d "|" 

With this line of code, you remove all |->(pipe) in the string.

2
  • 1
    I needed to remove dbl-quotes from a grepd string (e.g. "IPVanish-nyca20-VPN"). The | tr -d "\"" worked like a charm. +1 Commented Mar 5, 2024 at 21:05
  • Surprising that this is the only answer here that recommends tr; even more surprising that this is the first answer - after 13 years - to use tr in the answer. Hmmm - maybe that says something about Ubuntu (or its users) lol Anyway, here's more on tr from Dave McKay. Commented Mar 5, 2024 at 22:36

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.