133

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

150

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,477
81

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

string="|abcdefg|"
echo "${string:1:${#string}-2}"
Eliah Kagan
  • 117,780
Samus_
  • 1,128
65

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

jlunavtgrad
  • 759
  • 5
  • 4
  • 3
    This should be have been the top answer. You won't find any bash 4.1 on modern systems. :) – Artur Barseghyan Jul 09 '20 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. – a.t. Feb 19 '21 at 17:48
32

Another way is to use head & tail commands:

$ echo -n "|abcdefg|" | tail -c +2 | head -c -2
abcdefg
agabrys
  • 103
Zavior
  • 421
  • 4
  • 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! – Ain Tohvri Dec 13 '15 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 – Dmitry Khamitov Mar 27 '19 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. – progonkpa Jan 17 '23 at 13:13
  • Not working on the latest shell editions (at least on mac...). I get head: illegal byte count -- -2 – ElyashivLavi Sep 07 '23 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//|/}"
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
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
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
    I needed to remove dbl-quotes from a grepd string (e.g. "IPVanish-nyca20-VPN"). The | tr -d "\"" worked like a charm. +1 – Seamus Mar 05 '24 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. – Seamus Mar 05 '24 at 22:36
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