我有一个名为 readvar.sh 的脚本:
#! /bin/bash
a="$1"
echo "$a"
我想获取参数字面上地当用户输入时,
例如,如果用户运行:./readvar.sh \\
它应该输出\\
而不需要用引号将参数括起来。
那可能吗?
答案1
一般来说,你不能这样做。
如果运行./readvar.sh \\
,则编写命令的 shell 会解析命令行,将空格识别为单词分隔符,并将反斜杠识别为引用下一个字符(另一个反斜杠)。然后,它以两个单词./readvar.sh
和结束\
,并启动程序,./readvar.sh
将这两个单词放入启动进程的参数列表中。 (命令名称是参数 #0,它显示在argv[0]
C 程序中。)
请注意,如果用户输入./readvar.sh '\'
或,或者使用类似Perl 程序的bs='\'; ./readvar "$var"
内容启动脚本,您会得到类似的结果。system("./readvar.sh", "\\");
脚本通常无法知道发生了什么。
您可以做的就是以适合作为 shell 输入的格式打印所有参数,例如在 Bash 中使用
if [ "$#" -ne 0 ]; then
printf "%q " "$@"
fi
echo
请注意,输出是这样的,它可以在 Bash 中工作,但可能不能在标准 shell 中工作,因为它使用$'\n'
换行符等引号的形式。此外,\\
无论您使用\\
或启动脚本时,'\'
它都会输出。"\\"
同样在 Bash 中,您可能会滥用extdebug
。这会将 Bash 的 DEBUG 陷阱所看到的命令行安排在运行的命令的环境中:
export CMDLINE
trap 'CMDLINE=$BASH_COMMAND; true' DEBUG
shopt -s extdebug
但请注意,那里的命令行没有展开,所以如果您运行env abc=$var |grep CMD
,您会看到env abc=$var
,而不是展开的值。
当然,如果您的命令不是从采取额外步骤的 Bash shell 启动的,那么这将不起作用。如果您在进程树的较高位置有这样的 shell,CMDLINE
则可以将其设置为用于启动较早命令的命令。
现在,虽然存在这些棘手的解决方法,但对于脚本的用户来说,使用其他方法来实现脚本最终应该做的事情可能会更好,也更不令人惊讶。
答案2
您可以read
使用-r
标志进行调用:
-r Backslash does not act as an
escape character. The backslash
is considered to be part of the line.
In particular, a backslash-newline pair
may not then be used as a line
continuation.
所以:
IFS="" read -r a
echo "$a"
如果您输入“\”,将回显“\”。它还会保留空格(如果这不是目标,您可以删除 IFS 位)。
如果您只想将其作为参数传递,单引号应保持值不变。
./readvar.sh '\\'
读取var.sh:
#!/bin/bash
IFS="" read -r a
./usevar.sh "$a"
使用var.sh:
#!/bin/bash
echo "$1"
如果你输入\\
,readvar.sh
就会usevar.sh
回显\\
。
您需要 IFS 来保留文本开头和结尾的空格。