我有一个shell脚本与这段代码:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
但是条件代码总是执行,因为hg st总是打印至少一个换行符。
是否有一个简单的方法从$var中剥离空白(如PHP中的trim())?
or
有没有处理这个问题的标准方法?
我可以使用sed或AWK,但我认为有一个更优雅的解决方案来解决这个问题。
我有一个shell脚本与这段代码:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
但是条件代码总是执行,因为hg st总是打印至少一个换行符。
是否有一个简单的方法从$var中剥离空白(如PHP中的trim())?
or
有没有处理这个问题的标准方法?
我可以使用sed或AWK,但我认为有一个更优雅的解决方案来解决这个问题。
当前回答
"trim"函数删除所有水平空白:
ltrim () {
if [[ $# -eq 0 ]]; then cat; else printf -- '%s\n' "$@"; fi | perl -pe 's/^\h+//g'
return $?
}
rtrim () {
if [[ $# -eq 0 ]]; then cat; else printf -- '%s\n' "$@"; fi | perl -pe 's/\h+$//g'
return $?
}
trim () {
ltrim "$@" | rtrim
return $?
}
其他回答
当IFS变量被设置为其他变量时,我需要从脚本中删除空白。依赖Perl实现了这个目的:
# trim() { echo $1; } # This doesn't seem to work, as it's affected by IFS
trim() { echo "$1" | perl -p -e 's/^\s+|\s+$//g'; }
strings="after --> , <-- before, <-- both --> "
OLD_IFS=$IFS
IFS=","
for str in ${strings}; do
str=$(trim "${str}")
echo "str= '${str}'"
done
IFS=$OLD_IFS
Bash有一个称为参数展开的特性,它允许基于所谓的模式替换字符串(模式类似于正则表达式,但有基本的区别和限制)。 [flussence的原文:Bash有正则表达式,但它们隐藏得很好:]
下面演示如何从变量值中删除所有空白(甚至来自内部)。
$ var='abc def'
$ echo "$var"
abc def
# Note: flussence's original expression was "${var/ /}", which only replaced the *first* space char., wherever it appeared.
$ echo -n "${var//[[:space:]]/}"
abcdef
# Trim whitespace from both ends of specified parameter
trim () {
read -rd '' $1 <<<"${!1}"
}
# Unit test for trim()
test_trim () {
local foo="$1"
trim foo
test "$foo" = "$2"
}
test_trim hey hey &&
test_trim ' hey' hey &&
test_trim 'ho ' ho &&
test_trim 'hey ho' 'hey ho' &&
test_trim ' hey ho ' 'hey ho' &&
test_trim $'\n\n\t hey\n\t ho \t\n' $'hey\n\t ho' &&
test_trim $'\n' '' &&
test_trim '\n' '\n' &&
echo passed
Use:
var=`expr "$var" : "^\ *\(.*[^ ]\)\ *$"`
它去掉了开头和结尾的空格,我认为这是最基本的解决方案。不是Bash内置的,但'expr'是coreutils的一部分,所以至少不需要像sed或AWK这样的独立实用程序。
我将简单地使用sed:
function trim
{
echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
}
a)单行字符串使用示例
string=' wordA wordB wordC wordD '
trimmed=$( trim "$string" )
echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"
输出:
GIVEN STRING: | wordA wordB wordC wordD |
TRIMMED STRING: |wordA wordB wordC wordD|
b)多行字符串使用示例
string=' wordA
>wordB<
wordC '
trimmed=$( trim "$string" )
echo -e "GIVEN STRING: |$string|\n"
echo "TRIMMED STRING: |$trimmed|"
输出:
GIVEN STRING: | wordAA
>wordB<
wordC |
TRIMMED STRING: |wordAA
>wordB<
wordC|
c)最后说明: 如果你不喜欢使用函数,对于单行字符串,你可以简单地使用“更容易记住”的命令,比如:
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
例子:
echo " wordA wordB wordC " | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
输出:
wordA wordB wordC
在多行字符串上使用上述方法也可以,但请注意,它也会切断任何尾随/前导内部多行空间,就像GuruM在评论中注意到的那样
string=' wordAA
>four spaces before<
>one space before< '
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
输出:
wordAA
>four spaces before<
>one space before<
所以如果你介意保留这些空格,请使用我回答开头的函数!
d)解释sed语法“find and replace”在函数trim中使用的多行字符串:
sed -n '
# If the first line, copy the pattern to the hold buffer
1h
# If not the first line, then append the pattern to the hold buffer
1!H
# If the last line then ...
$ {
# Copy from the hold to the pattern buffer
g
# Do the search and replace
s/^[ \t]*//g
s/[ \t]*$//g
# print
p
}'