如何在没有开关-e的情况下找到“echo”语句并在Unix中替换“echo -e”

时间:2017-04-10 23:35:12

标签: linux shell unix

我需要修改我的所有unix shell脚本,所有实例以及当前和子目录中的所有文件,如下所示:

$ cat test.txt  ## original input file
echo "\nHello\n\tWorld 1"
echo "OK"
echo -e "\nHello\nWorld 2"
echo "OK!OK!!"
echo "Hello\nWorld 3"

修改为:

$ cat test.txt  ## desired form of file post-update
echo -e "\nHello\n\tWorld 1"
echo "OK"
echo -e "\nHello\nWorld 2"
echo "OK!OK!!"
echo -e "Hello\nWorld 3"

更多详情:

  1. echo "\n...\t..."(行:1和5,其中包含反斜杠字符串但不包含“-e”)到echo -e "\n...\t..."

  2. echo -e "\n...\t.."(第3行,不应再添加一个“-e”,它已经存在,无需修改此行)

  3. 来自echo "...."(第2行和第4行) - 无需更改,因为这些行不包含任何反斜杠字符。

  4. 需要在所有文件语句中的所有匹配项中将echo替换为echo -e

    • 如果“echo语句”包含任何反斜杠字符但没有带开关的“-e”。

    无需替换:

    • 如果echo语句包含任何反斜杠字符但已经echo -e,则无需更改
    • 如果“echo”语句不包含任何反斜杠字符,则无需添加-e - 因此无需更改。

    我试过了:

    $ grep -R "echo.*""\.*\\n.*" *| grep -v "echo.*-e" | sed 's/echo/& -e/g'
    

    输出:

    test.txt:echo -e "\nHello\n\tWorld 1"
    test.txt:echo -e "Hello\nWorld 3"
    

    它只显示要修改的行但不修改脚本。

    请有人帮助我。

1 个答案:

答案 0 :(得分:0)

初步警告

请注意,如果使用足够有趣/复杂的语法 - echo s命令替换,则下面的行为不会很好;那些后来eval的字符串;复合命令;命令从多个行的参数中分离出来;因此,我强烈建议手动审核更改并手动合并(使用git add -p之类的工具,如果内容属于版本控制,或vimdiff或类似的一般)。

按字面要求

rewrite_echos() {
  has_echo_re='((^|;|&)[[:space:]]*)echo([[:space:]])(.*)$'
  has_echo_e_re='(^|;|&)[[:space:]]*echo[[:space:]]+-n?en?[[:space:]]+'

  while IFS= read -r line; do
    [[ $line =~ $has_echo_re ]] || { printf '%s\n' "$line"; continue; }
    prefix=${BASH_REMATCH[1]}; suffix_chr=${BASH_REMATCH[3]}; content=${BASH_REMATCH[4]}

    [[ $line =~ $has_echo_e_re ]] && { printf '%s\n' "$line"; continue; }
    [[ $content = *"\\"* ]] || { printf '%s\n' "$line"; continue; }
    printf '%secho -e%s\n' "$prefix" "${suffix_chr}${content}"
  done
}

将其作为:

运行
rewrite_echos <test.txt

正确发出:

echo -e "\nHello\n\tWorld 1"
echo "OK"
echo -e "\nHello\nWorld 2"
echo "OK!OK!!"
echo -e "Hello\nWorld 3"

更正确:使用printf代替echo

请求的转换不同,下面给出的转换生成的输出适用于所有符合POSIX的shell。

rewrite_echos() {
  has_echo_re='((^|;|&)[[:space:]]*)echo([[:space:]])(.*)$'

  while IFS= read -r line; do
    [[ $line =~ $has_echo_re ]] || { printf '%s\n' "$line"; continue; }
    prefix=${BASH_REMATCH[1]}; suffix_chr=${BASH_REMATCH[3]}; content=${BASH_REMATCH[4]}

    [[ $content = *"\\"* ]] || { printf '%s\n' "$line"; continue; }
    if [[ $content =~ ^-e[[:space:]] ]]; then
      printf $'%sprintf \'%%b \'%s && printf \'\\\\n\'\n' "$prefix" "${suffix_chr}${content#-e[[:space:]]}"
    else
      printf $'%sprintf \'%%b \'%s && printf \'\\\\n\'\n' "$prefix" "${suffix_chr}${content}"
    fi
  done
}