22

我正在寻找仅使用 bash / 标准 Linux 命令可以按如下方式转换字符串的内容:

  1. 应删除围绕字符串的单引号
  2. 应删除围绕字符串的双引号
  3. 未加引号的字符串应保持不变
  4. 带有不匹配引号的字符串应保持不变
  5. 不围绕字符串的单引号应保留
  6. 不围绕字符串的双引号应保留

例如:

  • “食物”应该变成食物
  • “食物”应该变成食物
  • 食物应该保持不变
  • “食物”应该保持不变
  • “食物”应该保持不变
  • “食物”应该变成食物
  • “食物”应该变成食物
  • 食物应该保持不变
  • 'Foo"od' 应该变成 Foo"od
  • “食物”应该变成“食物”
  • 食物应该保持不变

谢谢!

4

7 回答 7

34

这应该这样做:

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

其中 in.txt 是:

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

而expected.txt 是:

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

您可以检查它们是否匹配:

diff -s <(sed "s/^\([\"']\)\(.*\)\1\$/\2/g" in.txt) expected.txt
于 2009-04-16T21:24:19.227 回答
24

你可以使用tr

echo "$string" | tr -d 'chars to delete' 

... 也有效,但是已知“tr”在更旧的(大约 Redhat 9-ish)发行版上存在问题。tr是 'translate' 的缩写,常用于管道转换输入。该-d选项仅表示“删除”。

大多数现代版本还包含预定义的宏来将上转换为下,从下转换为上,消除空白等。因此,如果您使用它,请花点时间了解它还有什么作用(请参阅帮助输出/手册页),派上用场。

于 2009-04-17T08:31:08.580 回答
16
VAR="'FOOD'"

VAR=$(eval echo $VAR)

说明:由于 shell 已经理解引号,您可以要求 shell 评估一个只回显带引号的字符串的命令,就像您自己键入它时一样。

在这里,eval echo $VAR扩展为,eval echo 'FOOD'因为引号实际上是 的值的一部分VAR。如果你遇到echo 'FOOD'你会得到的外壳FOOD(不带引号)。就是这样eval做的:它接受输入并像 shell 命令一样运行它。

⚠代码注入!

eval将脚本暴露给代码注入。

VAR=';ls -l'

VAR=$(eval echo $VAR)

将导致执行ls -l.

这里可能会注入更多有害代码。

于 2014-06-23T04:28:26.483 回答
9

您可能想使用sed ...

echo $mystring | sed -s "s/^\(\(\"\(.*\)\"\)\|\('\(.*\)'\)\)\$/\\3\\5/g"
于 2009-04-16T21:20:58.050 回答
4

只需使用 Bash 内置函数(即 Bash 参数扩展):

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 

有关 Bash 参数扩展的另一个示例,请参见:

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

于 2009-04-18T09:40:25.300 回答
2

也偶然发现了这一点。对于前三个测试用例,eval echo $string效果很好。为了让它适用于所有请求的案例和其他一些案例,我想出了这个(用bashand测试dash):

#!/bin/sh

stripquotes() {
    local firstchar="`substr "$1" 0 1`"
    local len=${#1}
    local ilast=$((${#1} - 1))
    local lastchar="`substr "$1" $(($len - 1))`"
    if [ "$firstchar" = '"' ] || [ "$firstchar" = "'" ] && [ $firstchar = $lastchar ]; then
        echo "`substr "$1" 1 $(($len - 2))`"
    else
        echo "$1"
    fi
}

# $1 = String.
# $2 = Start index.
# $3 = Length (optional). If unspecified or an empty string, the length of the
#      rest of the string is used.
substr() {
    local "len=$3"
    [ "$len" = '' ] && len=${#1}
    if ! (echo ${1:$2:$len}) 2>/dev/null; then
        echo "$1" | awk "{ print(substr(\$0, $(($2 + 1)), $len)) }"
    fi
}

var="'Food'"
stripquotes "$var"

var='"Food"'
stripquotes "$var"

var=Food
stripquotes "$var"

var=\'Food\"
stripquotes "$var"

var=\"Food\'
stripquotes "$var"

var="'Fo'od'"
stripquotes "$var"

var="\"Fo'od\""
stripquotes "$var"

var="Fo'od"
stripquotes "$var"

var="'Fo\"od'"
stripquotes "$var"

var="\"Fo\"od\""
stripquotes "$var"

var="Fo\"od"
stripquotes "$var"

# A string with whitespace should work too.
var="'F\"o 'o o o' o\"d'"
stripquotes "$var"

# Strings that start and end with the same character that isn't a quote or
# doublequote should stay the same.
var="TEST"
stripquotes "$var"

# An empty string should not cause errors.
var=
stripquotes "$var"

# Strings of length 2 that begin and end with a quote or doublequote should not
# cause errors.
var="''"
stripquotes "$var"
var='""'
stripquotes "$var"
于 2011-12-08T16:04:31.623 回答
1
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)"

它不能很好地处理边缘情况(例如空字符串),但它将作为起点。如果它们相同并且如果它们是 ' 或 "

于 2009-04-16T21:15:36.517 回答