bash - 快速转义任何字符串
bash - quickly escape any characters string
我正在寻找一个可以快速转义字符串的实用程序。这个任务太有用了,我找不到了
举个例子:
hisrmline 'h | g -E "^ [0-9]* exit$"'
如果我想手动转义,可以这样做:
'hisrmline '\''h | g -E "^ [0-9]* exit$"'\'''
但是费时费力,效率不高。所以我找到了 printf %q:
[xiaobai@xiaobai note]$ printf "%q" hisrmline 'h | g -E "^ [0-9]* exit$"'
hisrmlineh\ \|\ g\ -E\ \"\^\ \[0-9\]\*\ \ exit$\"[xiaobai@xiaobai note]$
[xiaobai@xiaobai note]$
输出错误,因为 hisrmlineh 被连接在一起,所以我缩小了字符串范围:
[xiaobai@xiaobai note]$ printf "%q" hisrmline 'h'
hisrmlineh[xiaobai@xiaobai note]$
[xiaobai@xiaobai note]$
我想要的是 hisrmline\ \'h\'
这对 grep 特别有用:
[xiaobai@xiaobai note]$ HISTTIMEFORMAT=""; history|grep -a --color=auto hisrmline\ \'h
7856 hisrmline 'hisrmline'
7857 hisrmline 'hisrmline'
7882 hisrmline 'h | g -E "^ [0-9]* exit[ ]*$"'
7883 hisrmline 'h | g -E "^ [0-9]* exit[ ]*$"'
7884 hisrmline 'h | g -E "'
7885 hisrmline 'h | g '
7886 hisrmline 'h | g'
7887 hisrmline 'h |'
7890 hisrmline 'h | g -E "^ [0-9]* exit$"'
7891 hisrmline 'h | g -E "^ [0-9]* exit$"'
7905 h|g 'hisrmline 'h | g -E "^ [0-9]* exit$"''
而且 grep -F 在处理嵌套单引号时不会让我的生活更轻松,我仍然必须手动转义单引号 '\'':
[xiaobai@xiaobai note]$ HISTTIMEFORMAT=""; history|grep -a --color=auto -F '[0-9]* exit$"'\'''
7889 h|g -aF 'h | g -E "^ [0-9]* exit$"'
7890 hisrmline 'h | g -E "^ [0-9]* exit$"'
7891 hisrmline 'h | g -E "^ [0-9]* exit$"'
7905 h|g 'hisrmline 'h | g -E "^ [0-9]* exit$"''
7911 h|g 'hisrmline 'h | g -E "^ [0-9]* exit$"''
7912 h|g 'hisrmline '"'"'h | g -E "^ [0-9]* exit$"'"'"'
是否有任何更简单的方法或任何现有实用程序来转义任何字符串的列表?
如果您正确引用命令行,那么 printf
应该可以工作,例如:
printf "%q\n" "hisrmline 'h'"
hisrmline\ \'h\'
或:
printf "%q\n" "hisrmline 'h | g -E \"^ [0-9]* exit$\"'"
hisrmline\ \'h\ \|\ g\ -E\ \"\^\ \[0-9\]\*\ \ exit$\"\'
编辑:您可能正在寻找这种转义:
IFS= read -r str<<"EOF"
hisrmline 'h | g -E "^ [0-9]* exit$"'
EOF
printf "%q\n" "$str"
hisrmline\ \'h\ \|\ g\ -E\ \"\^\ \[0-9\]\*\ \ exit$\"\'
[由@林果曜更新]
对于可能感兴趣的人,必须引用 EOF 以防止扩展,如@bize 所述:
没有引用的 EOF:
[xiaobai@xiaobai Downloads]$ IFS= read -r str<<EOF
> target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
> EOF
[xiaobai@xiaobai Downloads]$ printf "%q\n" "$str"
target=\'h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\'\;\ history\|grep\ -aF\ \"h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\"\;\ echo\ 73
[xiaobai@xiaobai Downloads]$
"EOF" 引用:
[xiaobai@xiaobai Downloads]$ IFS= read -r str<<"EOF"
> target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
> EOF
[xiaobai@xiaobai Downloads]$ printf "%q\n" "$str"
target=\'h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\'\;\ history\|grep\ -aF\ \"$target\"\;\ echo\ $\{#target\}
[xiaobai@xiaobai Downloads]$
仅在引用 "EOF":
的输出中提供正确的行为
[xiaobai@xiaobai Downloads]$ h|g -F target=\'h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\'\;\ history\|grep\ -aF\ \"$target\"\;\ echo\ $\{#target\}
7721 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
7725 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
7726 atarget='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
8297 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
8320 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
*h 是 export HISTTIMEFORMAT=""; history
*g is aliased to
grep -a --color=auto
的别名
直接使用 $ h|g -F "$str"
也有效。
处理 unicode 时,我必须在查询(历史、ls..等)源字符串之前将 LC_ALL= 分配给空(即 LC_ALL="en_US.utf8")。然后我必须将它切换到 LC_ALL=C 以使 printf %q 正常工作。
更新:
在评论中,您告诉我们您从历史记录中复制了这些行,并希望将它们重新插入到 shell 命令中。在 bash
中有 history expansion 可以访问部分历史记录或修改它。可能这已经是你想要的了。
否则你可以创建一个小命令来显示转义的历史:
IFS=$'\n' history | while read line ; do printf "%q\n" "$line"; done
您可以从该输出复制行并将它们插入到 shell 字符串中。如果您的 $HISTSIZE
很大,您还可以通过管道将其设置为 less。
如果您更频繁地需要此命令,您可以从中创建一个脚本文件或在 .bashrc
中创建一个函数
原答案
假设要使用 '
作为字符串分隔符,您可以使用以下 bash
表达式:
string="hisrmline 'h | g -E \"^ [0-9]* exit$\"'"
echo "${string//\'/\\'}"
现在您可以使用bash中的字符串了。如果你想在 grep
或其他使用正则表达式的程序中使用它,你需要转义更多的字符。但是 grep 支持选项 -F
。如果传递它,模式将作为固定字符串处理,而不是正则表达式。
亲吻方法:
printf "%q" "$(cat <<"_up_to_here_"
hisrmline 'h | g -E "^ [0-9]* exit$"'
_up_to_here_
)"
"_up_to_here_"
和 _up_to_here_
之间的任何内容都将被正确引用。
请注意:
第一个 _up_to_here_
被引用以防止在下一行或下一行 (S) 中扩展任何 $variable。
评论:cat
的使用旨在使命令简单,任何正确转换为 read
的尝试都需要广泛的知识:不是 KISS aproach。
我正在寻找一个可以快速转义字符串的实用程序。这个任务太有用了,我找不到了
举个例子:
hisrmline 'h | g -E "^ [0-9]* exit$"'
如果我想手动转义,可以这样做:
'hisrmline '\''h | g -E "^ [0-9]* exit$"'\'''
但是费时费力,效率不高。所以我找到了 printf %q:
[xiaobai@xiaobai note]$ printf "%q" hisrmline 'h | g -E "^ [0-9]* exit$"'
hisrmlineh\ \|\ g\ -E\ \"\^\ \[0-9\]\*\ \ exit$\"[xiaobai@xiaobai note]$
[xiaobai@xiaobai note]$
输出错误,因为 hisrmlineh 被连接在一起,所以我缩小了字符串范围:
[xiaobai@xiaobai note]$ printf "%q" hisrmline 'h'
hisrmlineh[xiaobai@xiaobai note]$
[xiaobai@xiaobai note]$
我想要的是 hisrmline\ \'h\'
这对 grep 特别有用:
[xiaobai@xiaobai note]$ HISTTIMEFORMAT=""; history|grep -a --color=auto hisrmline\ \'h
7856 hisrmline 'hisrmline'
7857 hisrmline 'hisrmline'
7882 hisrmline 'h | g -E "^ [0-9]* exit[ ]*$"'
7883 hisrmline 'h | g -E "^ [0-9]* exit[ ]*$"'
7884 hisrmline 'h | g -E "'
7885 hisrmline 'h | g '
7886 hisrmline 'h | g'
7887 hisrmline 'h |'
7890 hisrmline 'h | g -E "^ [0-9]* exit$"'
7891 hisrmline 'h | g -E "^ [0-9]* exit$"'
7905 h|g 'hisrmline 'h | g -E "^ [0-9]* exit$"''
而且 grep -F 在处理嵌套单引号时不会让我的生活更轻松,我仍然必须手动转义单引号 '\'':
[xiaobai@xiaobai note]$ HISTTIMEFORMAT=""; history|grep -a --color=auto -F '[0-9]* exit$"'\'''
7889 h|g -aF 'h | g -E "^ [0-9]* exit$"'
7890 hisrmline 'h | g -E "^ [0-9]* exit$"'
7891 hisrmline 'h | g -E "^ [0-9]* exit$"'
7905 h|g 'hisrmline 'h | g -E "^ [0-9]* exit$"''
7911 h|g 'hisrmline 'h | g -E "^ [0-9]* exit$"''
7912 h|g 'hisrmline '"'"'h | g -E "^ [0-9]* exit$"'"'"'
是否有任何更简单的方法或任何现有实用程序来转义任何字符串的列表?
如果您正确引用命令行,那么 printf
应该可以工作,例如:
printf "%q\n" "hisrmline 'h'"
hisrmline\ \'h\'
或:
printf "%q\n" "hisrmline 'h | g -E \"^ [0-9]* exit$\"'"
hisrmline\ \'h\ \|\ g\ -E\ \"\^\ \[0-9\]\*\ \ exit$\"\'
编辑:您可能正在寻找这种转义:
IFS= read -r str<<"EOF"
hisrmline 'h | g -E "^ [0-9]* exit$"'
EOF
printf "%q\n" "$str"
hisrmline\ \'h\ \|\ g\ -E\ \"\^\ \[0-9\]\*\ \ exit$\"\'
[由@林果曜更新]
对于可能感兴趣的人,必须引用 EOF 以防止扩展,如@bize 所述:
没有引用的 EOF:
[xiaobai@xiaobai Downloads]$ IFS= read -r str<<EOF
> target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
> EOF
[xiaobai@xiaobai Downloads]$ printf "%q\n" "$str"
target=\'h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\'\;\ history\|grep\ -aF\ \"h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\"\;\ echo\ 73
[xiaobai@xiaobai Downloads]$
"EOF" 引用:
[xiaobai@xiaobai Downloads]$ IFS= read -r str<<"EOF"
> target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
> EOF
[xiaobai@xiaobai Downloads]$ printf "%q\n" "$str"
target=\'h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\'\;\ history\|grep\ -aF\ \"$target\"\;\ echo\ $\{#target\}
[xiaobai@xiaobai Downloads]$
仅在引用 "EOF":
的输出中提供正确的行为[xiaobai@xiaobai Downloads]$ h|g -F target=\'h\ \|\ g\ -E\ -i\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g\[\ \]\"\ -e\ \"\^\[\ \]+\[0-9\]+\ \ .\*\[\|\&\;\ \]+g$\"\'\;\ history\|grep\ -aF\ \"$target\"\;\ echo\ $\{#target\}
7721 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
7725 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
7726 atarget='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
8297 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
8320 target='h | g -E -i -e "^[ ]+[0-9]+ .*[|&; ]+g[ ]" -e "^[ ]+[0-9]+ .*[|&; ]+g$"'; history|grep -aF "$target"; echo ${#target}
*h 是 export HISTTIMEFORMAT=""; history
*g is aliased to
grep -a --color=auto
直接使用 $ h|g -F "$str"
也有效。
处理 unicode 时,我必须在查询(历史、ls..等)源字符串之前将 LC_ALL= 分配给空(即 LC_ALL="en_US.utf8")。然后我必须将它切换到 LC_ALL=C 以使 printf %q 正常工作。
更新:
在评论中,您告诉我们您从历史记录中复制了这些行,并希望将它们重新插入到 shell 命令中。在 bash
中有 history expansion 可以访问部分历史记录或修改它。可能这已经是你想要的了。
否则你可以创建一个小命令来显示转义的历史:
IFS=$'\n' history | while read line ; do printf "%q\n" "$line"; done
您可以从该输出复制行并将它们插入到 shell 字符串中。如果您的 $HISTSIZE
很大,您还可以通过管道将其设置为 less。
如果您更频繁地需要此命令,您可以从中创建一个脚本文件或在 .bashrc
原答案
假设要使用 '
作为字符串分隔符,您可以使用以下 bash
表达式:
string="hisrmline 'h | g -E \"^ [0-9]* exit$\"'"
echo "${string//\'/\\'}"
现在您可以使用bash中的字符串了。如果你想在 grep
或其他使用正则表达式的程序中使用它,你需要转义更多的字符。但是 grep 支持选项 -F
。如果传递它,模式将作为固定字符串处理,而不是正则表达式。
亲吻方法:
printf "%q" "$(cat <<"_up_to_here_"
hisrmline 'h | g -E "^ [0-9]* exit$"'
_up_to_here_
)"
"_up_to_here_"
和 _up_to_here_
之间的任何内容都将被正确引用。
请注意:
第一个 _up_to_here_
被引用以防止在下一行或下一行 (S) 中扩展任何 $variable。
评论:cat
的使用旨在使命令简单,任何正确转换为 read
的尝试都需要广泛的知识:不是 KISS aproach。