为何Bash中sed会移除字符串首尾空格?如何避免?
Bash脚本中sed意外移除文件名首尾空格的原因与解决方法
问题场景
有一个批量替换文件名字符的Bash脚本,运行时发现sed命令会意外移除文件名的首尾空格,但在终端单独执行sed命令时却不会出现这个问题。以下是最小可复现示例(MRE):
脚本代码
#!/usr/bin/env bash declare -A char_map char_map["1"]="-" char_map["2"]="+" filelist=$(echo -e "./mydir/ number1number2withspaceoutside \n./mydir/number1 number2 with space inside") while IFS= read current_file do [[ -z "$current_file" ]] && continue path=$(dirname "$current_file") filename=$(basename "$current_file") fixed_filename="$filename" for bad in "${!char_map[@]}" do echo "before sed: '$fixed_filename'" fixed_filename=$(echo $fixed_filename | sed s/$bad/${char_map[$bad]}/g) echo "after sed: '$fixed_filename'" echo "--------------------" done if [ "$fixed_filename" == "$filename" ] then echo "nothing bad found: $current_file" continue fi echo "moving '$current_file' to '$path/$fixed_filename'" echo "================================================================================================" done < <(echo "$filelist")
脚本输出
before sed: ' number1number2withspaceoutside ' after sed: 'number1number+withspaceoutside' -------------------- before sed: 'number1number+withspaceoutside' after sed: 'number-number+withspaceoutside' -------------------- moving './mydir/ number1number2withspaceoutside ' to './mydir/number-number+withspaceoutside' ================================================================================================ before sed: 'number1 number2 with space inside' after sed: 'number1 number+ with space inside' -------------------- before sed: 'number1 number+ with space inside' after sed: 'number- number+ with space inside' -------------------- moving './mydir/number1 number2 with space inside' to './mydir/number- number+ with space inside' ================================================================================================
终端单独测试
执行命令:
echo " bla " | sed s/l/-/g
输出:
' b-a '
原因分析
问题根本不在sed,而是Bash的单词拆分(Word Splitting)机制:
脚本中执行echo $fixed_filename时,变量fixed_filename没有被双引号包裹。Bash在处理未加引号的变量展开时,会把所有连续的空白字符(空格、换行、制表符等)当作单词分隔符,同时自动忽略字符串首尾的空白。这就导致传给sed的内容已经丢失了首尾空格,sed处理后的结果自然也没有首尾空格。
而终端单独测试时,echo " bla "给字符串加了双引号,Bash不会进行单词拆分,首尾空格被完整保留,所以sed处理后也能保留首尾空格。
解决方法
只需要给echo命令中的变量加上双引号,同时为了避免sed替换表达式中的特殊字符问题,最好也给sed的命令加上双引号:
修改脚本中的sed执行行:
fixed_filename=$(echo "$fixed_filename" | sed "s/$bad/${char_map[$bad]}/g")
修改后的脚本输出示例
第一个文件的处理会变成:
before sed: ' number1number2withspaceoutside ' after sed: ' number1number+withspaceoutside ' -------------------- before sed: ' number1number+withspaceoutside ' after sed: ' number-number+withspaceoutside ' -------------------- moving './mydir/ number1number2withspaceoutside ' to './mydir/ number-number+withspaceoutside '
首尾空格被完整保留,符合预期。
内容的提问来源于stack exchange,提问作者Ovski
相关产品推荐
相关产品推荐

