如何从Bashvariables修剪空白?
我有这个代码的shell脚本:
var=`hg st -R "$path"` if [ -n "$var" ]; then echo $var fi
但是条件代码总是执行,因为hg st
总是打印至less一个换行符。
- 有没有一种简单的方法来从
$var
删除空白(如PHP中的trim()
)?
要么
- 有没有处理这个问题的标准方式?
我可以使用sed或AWK ,但是我想认为这个问题有一个更优雅的解决scheme。
我们定义一个包含前导,尾随和中间空格的variables:
FOO=' test test test ' echo -e "FOO='${FOO}'" # > FOO=' test test test ' echo -e "length(FOO)==${#FOO}" # > length(FOO)==16
如何删除所有的空格(在tr
中用[:space:]
表示):
FOO=' test test test ' FOO_NO_WHITESPACE="$(echo -e "${FOO}" | tr -d '[:space:]')" echo -e "FOO_NO_WHITESPACE='${FOO_NO_WHITESPACE}'" # > FOO_NO_WHITESPACE='testtesttest' echo -e "length(FOO_NO_WHITESPACE)==${#FOO_NO_WHITESPACE}" # > length(FOO_NO_WHITESPACE)==12
如何仅删除前导空格:
FOO=' test test test ' FOO_NO_LEAD_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//')" echo -e "FOO_NO_LEAD_SPACE='${FOO_NO_LEAD_SPACE}'" # > FOO_NO_LEAD_SPACE='test test test ' echo -e "length(FOO_NO_LEAD_SPACE)==${#FOO_NO_LEAD_SPACE}" # > length(FOO_NO_LEAD_SPACE)==15
如何只删除尾随空白:
FOO=' test test test ' FOO_NO_TRAIL_SPACE="$(echo -e "${FOO}" | sed -e 's/[[:space:]]*$//')" echo -e "FOO_NO_TRAIL_SPACE='${FOO_NO_TRAIL_SPACE}'" # > FOO_NO_TRAIL_SPACE=' test test test' echo -e "length(FOO_NO_TRAIL_SPACE)==${#FOO_NO_TRAIL_SPACE}" # > length(FOO_NO_TRAIL_SPACE)==15
如何去除前后空格 – 链接sed
s:
FOO=' test test test ' FOO_NO_EXTERNAL_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" echo -e "FOO_NO_EXTERNAL_SPACE='${FOO_NO_EXTERNAL_SPACE}'" # > FOO_NO_EXTERNAL_SPACE='test test test' echo -e "length(FOO_NO_EXTERNAL_SPACE)==${#FOO_NO_EXTERNAL_SPACE}" # > length(FOO_NO_EXTERNAL_SPACE)==14
另外,如果你的bash支持它,你可以replaceecho -e "${FOO}" | sed ...
echo -e "${FOO}" | sed ...
sed ... <<<${FOO}
(尾随空格):
FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
一个简单的答案是:
echo " lol " | xargs
Xargs会为你做修整。 这是一个命令/程序,没有参数,返回修剪的string,就这么简单!
注意:这不会删除内部空间,所以"foo bar"
保持不变。 它不会成为"foobar"
。
有一种解决scheme只使用Bash内置的通配符 :
var=" abc " # remove leading whitespace characters var="${var#"${var%%[![:space:]]*}"}" # remove trailing whitespace characters var="${var%"${var##*[![:space:]]}"}" echo "===$var==="
这里的function相同:
trim() { local var="$*" # remove leading whitespace characters var="${var#"${var%%[![:space:]]*}"}" # remove trailing whitespace characters var="${var%"${var##*[![:space:]]}"}" echo -n "$var" }
您将string以引用的forms进行修剪。 例如:
trim " abc "
这个解决scheme的一个好处是,它可以与任何POSIX兼容的shell一起工作。
参考
- 从Bashvariables ( 原始源 ) 删除前导和尾随空白
Bash有一个称为参数扩展的特性,除此之外,它允许基于所谓模式的stringreplace(模式类似于正则expression式,但是存在基本的差异和限制)。 [flussence的原始行:Bash有正则expression式,但是它们隐藏得很好:]
以下演示如何从一个variables值中删除所有的空白(甚至从内部)。
$ 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
你可以简单地用echo
来修剪:
foo=" qsdqsd qsdqs q qs " # Not trimmed echo \'$foo\' # Trim foo=`echo $foo` # Trimmed echo \'$foo\'
从Bash指南部分globbing
在参数扩展中使用extglob
#Turn on extended globbing shopt -s extglob #Trim leading and trailing whitespace from a variable x=${x##+([[:space:]])}; x=${x%%+([[:space:]])} #Turn off extended globbing shopt -u extglob
下面是一个包含在函数中的相同function(注意:需要引用传递给函数的inputstring):
trim() { # Determine if 'extglob' is currently on. local extglobWasOff=1 shopt extglob >/dev/null && extglobWasOff=0 (( extglobWasOff )) && shopt -s extglob # Turn 'extglob' on, if currently turned off. # Trim leading and trailing whitespace local var=$1 var=${var##+([[:space:]])} var=${var%%+([[:space:]])} (( extglobWasOff )) && shopt -u extglob # If 'extglob' was off before, turn it back off. echo -n "$var" # Output trimmed string. }
用法:
string=" abc def ghi "; #need to quote input-string to preserve internal white-space if any trimmed=$(trim "$string"); echo "$trimmed";
#!/bin/sh trim() { trimmed=$1 trimmed=${trimmed%% } trimmed=${trimmed## } echo "$trimmed" } HELLO_WORLD=$(trim "hello world ") FOO_BAR=$(trim " foo bar") BOTH_SIDES=$(trim " both sides ") echo "'${HELLO_WORLD}', '${FOO_BAR}', '${BOTH_SIDES}'"
你可以用tr
删除换行符:
var=`hg st -R "$path" | tr -d '\n'` if [ -n $var ]; then echo $var done
通过启用Bash的扩展模式匹配function( shopt -s extglob
),您可以使用以下命令:
{trimmed##*( )}
去除任意数量的领先空间。
# 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
我一直用sed来完成
var=`hg st -R "$path" | sed -e 's/ *$//'`
如果有一个更优雅的解决scheme,我希望有人张贴。
为了从string的开头和结尾删除所有的空格(包括行尾字符):
echo $variable | xargs echo -n
这也将删除重复的空间:
echo " this string has a lot of spaces " | xargs echo -n
产生:“这个string有很多空格”
对不起所有人,在我的脚本的其他地方有一个问题,我认为 var
有一个尾随的换行符,但事实并非如此。 命令replace条自动跟随换行符,如下所述: http : //tldp.org/LDP/abs/html/commandsub.html 。
有很多答案,但我仍然相信我刚刚写的脚本是值得提及的,因为:
- 它已经在shell bash / dash / busybox shell中成功testing过了
- 它是非常小的
- 它不依赖于外部命令,也不需要fork( – >快速和低资源使用)
- 它按预期工作:
- 它从开始和结束剥离所有空格和制表符,但不是更多
- 重要的是:它不会从string中间删除任何东西(许多其他答案),甚至换行符也会保留下来
- 特殊:
"$*"
使用一个空格连接多个参数。 如果你想修剪&只输出第一个参数,请使用"$1"
- 如果没有匹配的文件名模式等问题
剧本:
trim() { local s2 s="$*" # note: the brackets in each of the following two lines contain one space # and one tab until s2="${s#[ ]}"; [ "$s2" = "$s" ]; do s="$s2"; done until s2="${s%[ ]}"; [ "$s2" = "$s" ]; do s="$s2"; done echo "$s" }
用法:
mystring=" here is something " mystring=$(trim "$mystring") echo ">$mystring<"
输出:
>here is something<
我已经看到脚本只是使用variables赋值来完成这项工作:
$ xyz=`echo -e 'foo \n bar'` $ echo $xyz foo bar
空格会自动合并和裁剪。 必须小心shell元字符(潜在的注入风险)。
我还build议在shell条件中始终使用双引号variablesreplace:
if [ -n "$var" ]; then
因为variables中的-o或其他内容可以修改你的testing参数。
你可以使用老派tr
。 例如,这将返回git仓库中已修改文件的数量,删除空格。
MYVAR=`git ls-files -m|wc -l|tr -d ' '`
var=' abc ' trimmed=$(echo $var)
这对我工作:
text=" trim my edges " trimmed=$text trimmed=${trimmed##+( )} #Remove longest matching series of spaces from the front trimmed=${trimmed%%+( )} #Remove longest matching series of spaces from the back echo "<$trimmed>" #Adding angle braces just to make it easier to confirm that all spaces are removed #Result <trim my edges>
为了将相同的结果放在较less的行上:
text=" trim my edges " trimmed=${${text##+( )}%%+( )}
使用AWK:
echo $var | awk '{gsub(/^ +| +$/,"")}1'
这里有一个trim()函数,可以修整和规范空白
#!/bin/bash function trim { echo $* } echo "'$(trim " one two three ")'" # 'one two three'
另一个使用正则expression式的变体。
#!/bin/bash function trim { local trimmed="$@" if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]] then trimmed=${BASH_REMATCH[1]} fi echo "$trimmed" } echo "'$(trim " one two three ")'" # 'one two three'
这并不存在不必要的通配问题,而且内部空白也是未修改的(假设$IFS
被设置为默认值,即' \t\n'
)。
它可以读取第一个换行符(不包括它)或string的末尾(以先到者为准),并去除前导空格和尾部空格以及\t
字符的任意组合。 如果你想保留多行(也可以去掉前导和尾随的换行符),可以使用read -r -d '' var << eof
来代替。 但是,请注意,如果您的input恰好包含\neof
,它将在之前被截断。 (即使将它们添加到$ IFS,其他forms的空白,即\r
, \f
和\v
也不会被去除。
read -r var << eof $var eof
分配忽略前导和尾随空白,因此可以用于修剪:
$ var=`echo ' hello'`; echo $var hello
我会简单地使用sed:
function trim { echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' }
a)单行string使用示例
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的使用示例
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)最后说明:
如果你不喜欢使用函数,对于单行string,你可以简单地使用一个“更容易记住”的命令,如:
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
在多行string中使用上面的代码也是可以的 ,但是请注意,它也会削减任何尾随/领先的内部多个空间,就像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<
所以,如果你不介意保留这些空格,请在我的答案开始处使用该function!
d)函数trim中使用的多行string中的sed语法“find and replace”的说明:
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 }'
# Strip leading and trailing white space (new line inclusive). trim(){ [[ "$1" =~ ^[[:space:]]*(.*[^[:space:]])[[:space:]]*$ ]] printf "%s" "${BASH_REMATCH[1]}" }
要么
# Strip leading white space (new line inclusive). ltrim(){ [[ "$1" =~ ^[[:space:]]*(.*[^[:space:]]) ]] printf "%s" "${BASH_REMATCH[1]}" } # Strip trailing white space (new line inclusive). rtrim(){ [[ "$1" =~ ^[[:space:]]*(.*[^[:space:]])[[:space:]]*$ ]] printf "%s" "${BASH_REMATCH[1]}" } # Strip leading and trailing white space (new line inclusive). trim(){ printf "%s" "$(rtrim "$(ltrim "$1")")" }
要么
# Strip leading and trailing specified characters. ex: str=$(trim "$str" $'\n a') trim(){ if [ "$2" ]; then trim_chrs="$2" else trim_chrs="[:space:]" fi [[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]] printf "%s" "${BASH_REMATCH[1]}" }
要么
# Strip leading specified characters. ex: str=$(ltrim "$str" $'\n a') ltrim(){ if [ "$2" ]; then trim_chrs="$2" else trim_chrs="[:space:]" fi [[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]] printf "%s" "${BASH_REMATCH[1]}" } # Strip trailing specified characters. ex: str=$(rtrim "$str" $'\n a') rtrim(){ if [ "$2" ]; then trim_chrs="$2" else trim_chrs="[:space:]" fi [[ "$1" =~ ^(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]] printf "%s" "${BASH_REMATCH[1]}" } # Strip leading and trailing specified characters. ex: str=$(trim "$str" $'\n a') trim(){ printf "%s" "$(rtrim "$(ltrim "$1" "$2")" "$2")" }
要么
build立在moskit's expr的基础上
# Strip leading and trailing white space (new line inclusive). trim(){ printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"`" }
要么
# Strip leading white space (new line inclusive). ltrim(){ printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)"`" } # Strip trailing white space (new line inclusive). rtrim(){ printf "%s" "`expr "$1" : "^\(.*[^[:space:]]\)[[:space:]]*$"`" } # Strip leading and trailing white space (new line inclusive). trim(){ printf "%s" "$(rtrim "$(ltrim "$1")")" }
#!/bin/bash function trim { typeset trimVar eval trimVar="\${$1}" read trimVar << EOTtrim $trimVar EOTtrim eval $1=\$trimVar } # Note that the parameter to the function is the NAME of the variable to trim, # not the variable contents. However, the contents are trimmed. # Example of use: while read aLine do trim aline echo "[${aline}]" done < info.txt # File info.txt contents: # ------------------------------ # ok hello there $ # another line here $ #and yet another $ # only at the front$ #$ # Output: #[ok hello there] #[another line here] #[and yet another] #[only at the front] #[]
To remove spaces and tabs from left to first word, enter:
echo " This is a test" | sed "s/^[ \t]*//"
cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html
This will remove all the whitespaces from your String,
VAR2="${VAR2//[[:space:]]/}"
/
replaces the first occurrence and //
all occurrences of whitespaces in the string. Ie all white spaces get replaced by – nothing
This trims multiple spaces of the front and end
whatever=${whatever%% *}
whatever=${whatever#* }
This is the simplest method I've seen. It only uses Bash, it's only a few lines, the regexp is simple, and it matches all forms of whitespace:
if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]] then test=${BASH_REMATCH[1]} fi
Here is a sample script to test it with:
test=$(echo -e "\n \t Spaces and tabs and newlines be gone! \t \n ") echo "Let's see if this works:" echo echo "----------" echo -e "Testing:${test} :Tested" # Ugh! echo "----------" echo echo "Ugh! Let's fix that..." if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]] then test=${BASH_REMATCH[1]} fi echo echo "----------" echo -e "Testing:${test}:Tested" # "Testing:Spaces and tabs and newlines be gone!" echo "----------" echo echo "Ah, much better."
I created the following functions. I am not sure how portable printf is, but the beauty of this solution is you can specify exactly what is "white space" by adding more character codes.
iswhitespace() { n=`printf "%d\n" "'$1'"` if (( $n != "13" )) && (( $n != "10" )) && (( $n != "32" )) && (( $n != "92" )) && (( $n != "110" )) && (( $n != "114" )); then return 0 fi return 1 } trim() { i=0 str="$1" while (( i < ${#1} )) do char=${1:$i:1} iswhitespace "$char" if [ "$?" -eq "0" ]; then str="${str:$i}" i=${#1} fi (( i += 1 )) done i=${#str} while (( i > "0" )) do (( i -= 1 )) char=${str:$i:1} iswhitespace "$char" if [ "$?" -eq "0" ]; then (( i += 1 )) str="${str:0:$i}" i=0 fi done echo "$str" } #Call it like so mystring=`trim "$mystring"`