views:

2038

answers:

5

Hello Stack Overflow :-)

I'm looking for something that will translate a string as follows, using only bash / standard Linux commands:

  1. Single-quotes surrounding a string should be removed
  2. Double-quotes surrounding a string should be removed
  3. Unquoted strings should remain the same
  4. Strings with unmatched surrounding quotes should remain the same
  5. Single-quotes that don't surround the string should remain
  6. Double-quotes that don't surround the string should remain

For example:

  • 'Food' should become Food
  • "Food" should become Food
  • Food should remain the same
  • 'Food" should remain the same
  • "Food' should remain the same
  • 'Fo'od' should become Fo'od
  • "Fo'od" should become Fo'od
  • Fo'od should remain the same
  • 'Fo"od' should become Fo"od
  • "Fo"od" should become Fo"od
  • Fo"od should remain the same

Thank you!

+1  A: 
python -c "import sys;a=sys.stdin.read();a=a.strip();print (a[1:-1] if a[0]==a[-1] and a[0] in \"'\\\"\" else a)"

it doesn't handle edge cases extremely well (such as an empty string), but it will serve as a starting point. It works by striping the front and back character if they are the same and if they are ' or "

cobbal
I suppose, python is a standard Linux command nowadays...
Lucas Jones
Jason explicitly said that he wants bash / standard Linux commands.Even though python is shipped with most of the commonly used distros, it is certainly not standard. If you install a basic Debian system, for example, it doesn't include python.
Flávio Amieiro
+5  A: 

You probably want to use sed...

echo $mystring | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"
Varkhan
It fails in a few cases.
rq
I have not idea if it works, but +1 for the awesomeness of your sed command :)
sigjuice
This is very close, but just a teeny bit off.echo \"fo\"bar\' | sed -s "s/^\(\"\(.*\)\"\)\|\(\'\(.*\)\'\)\$/\\2/g"Got: fobar'Expected: "fo"bar'
Yes... for some reason I can't fathom, the last $ stubbornly refuses to match the end of my string. Working on it...
Varkhan
Seems to work now... some parentheses were missing...
Varkhan
PERFECT! Thank you!
Also, quote your parameter expansion.
lhunath
+9  A: 

This should do it:

sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt

Where in.txt is:

"Fo'od'
'Food'
"Food"
"Fo"od'
Food
'Food"
"Food'
'Fo'od'
"Fo'od"
Fo'od
'Fo"od'
"Fo"od"
Fo"od

And expected.txt is:

"Fo'od'
Food
Food
"Fo"od'
Food
'Food"
"Food'
Fo'od
Fo'od
Fo'od
Fo"od
Fo"od
Fo"od

You can check they match with:

diff -s <(sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt) expected.txt
rq
Very close :-)echo \"fo\"bar\' | sed "s/\([\"']\)\(.*\)\1/\2/g"Got: fobar'Expected: "fo"bar'
Great! Just go changing the requirements after the coding is done ;-) updated for that case.
rq
Here's one final requirements change :-)echo \"fo\'bar\' | sed -e "s/\([\"']\)\(.*\)\1\$/\2/g"Got: "fobarExpected: "fo'bar'
I hate regular expressions now.
rq
PERFECT! Thank you!
+1 for an entertaining contest. :) Deleting my proven-to-be-dodgy sed post accordingly.
sgreeve
+1 for well structured answer!
dfa
+1 for proving that 'Some people, when confronted with a problem, think“I know, I'll use regular expressions.” Now they have two problems.' Is as true as it gets!
Flávio Amieiro
+0 for useless of cat :p http://partmaps.org/era/unix/award.html#cat
sigjuice
A: 

echo $string | tr -d 'chars to delete' also works, however 'tr' is known to be problematic on much older distros.

Tim Post
+1  A: 

Just using Bash builtins (i.e. Bash parameter expansion):

IFS=' ' 

food_strings=( "'Food'" '"Food"' Food "'Food\"" "\"Food'" "'Fo'od'" "\"Fo'od\"" "Fo'od" "'Fo\"od'" '"Fo"od"' 'Fo"od'  )  

for food in ${food_strings[@]}; do 

   [[ "${food#\'}" != "$food" ]] && [[ "${food%\'}" != "$food" ]] && { food="${food#\'}"; food="${food%\'}"; } 

   [[ "${food#\"}" != "$food" ]] && [[ "${food%\"}" != "$food" ]] && { food="${food#\"}"; food="${food%\"}"; } 

   echo "$food"

done

For yet another example of Bash parameter expansion see:

http://codesnippets.joyent.com/posts/show/1816