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 Answers10

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/'
Kris Harper
  • 13,705
82

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

string="|abcdefg|"
echo "${string:1:${#string}-2}"
Eliah Kagan
  • 119,640
Samus_
  • 1,146
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

34

Another way is to use head & tail commands:

$ echo -n "|abcdefg|" | tail -c +2 | head -c -2
abcdefg
agabrys
  • 103
Zavior
  • 441
  • 4
  • 4
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//|/}"
Zombo
  • 1
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
$ 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.

Brian
  • 21
2

You can use this:

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

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

3UMF
  • 171
  • 1
  • 1
  • 6
2

Small and universal solution:

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

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

expr "|abcdef" : '|*\([^|]*\)|*'
Tosi Do
  • 21