Bash 捕获逐字命令行(包括引号!)以调用内部脚本

Bash 捕获逐字命令行(包括引号!)以调用内部脚本,bash,shell,Bash,Shell,我正在尝试编写一个“phone home”脚本,它将准确的命令行(包括使用的任何单引号或双引号)记录到MySQL数据库中。作为后端,我有一个包装数据库的cgi脚本。脚本本身在cgi脚本上调用curl,并将各种参数作为参数包括在内,包括verbatim命令行 显然,我在这里有很多事情要做,我已经被困在bash阶段了。目前,我甚至无法让bash逐字打印提供的参数: 期望输出: 使用echo: caller.sh: echo "$@" printf %q $@ printf "\n" 给出: $

我正在尝试编写一个“phone home”脚本,它将准确的命令行(包括使用的任何单引号或双引号)记录到MySQL数据库中。作为后端,我有一个包装数据库的cgi脚本。脚本本身在cgi脚本上调用curl,并将各种参数作为参数包括在内,包括verbatim命令行

显然,我在这里有很多事情要做,我已经被困在bash阶段了。目前,我甚至无法让bash逐字打印提供的参数:

期望输出: 使用echo: caller.sh:

echo "$@"
printf %q $@
printf "\n"
给出:

$ ./caller.sh -f -hello -q "blah"
-f hello -q blah
$ ./caller.sh -f hello -q "blah"
-fhello-qblah
(我还尝试了
echo$@
echo$*

使用printf%q: caller.sh:

echo "$@"
printf %q $@
printf "\n"
给出:

$ ./caller.sh -f -hello -q "blah"
-f hello -q blah
$ ./caller.sh -f hello -q "blah"
-fhello-qblah
(我还尝试了打印%q“$@”)


我不仅希望有人帮助我解决bash问题,而且希望有人能就如何以更整洁的方式实现这个“电话之家”提供更多的建议

您无法编写caller.sh来区分在shell上调用的这两个命令:

./caller.sh -f -hello -q "blah"
./caller.sh -f -hello -q blah
有完全相同的

如果要确保命令接收特殊字符,请将参数用单引号括起来:

./caller.sh -f -hello -q '"blah"'
或者如果只想将一个参数传递给调用方.sh:

./caller.sh '-f -hello -q "blah"'

我知道您想捕获调用方给出的参数

首先,调用方使用的引号用于在解释调用时进行保护。但它们不是作为论据存在的

举个例子:如果有人用一个参数“Hello World!”调用你的脚本,在Hello和World之间有两个空格。然后,您必须始终在脚本中保护1美元,以免丢失此信息

如果要正确记录所有转义参数(例如,在它们包含连续空格的情况下…),则必须使用带双引号的“$@”。“$@”相当于“$1”、“$2”、“$3”、“$4”等

因此,为了记录参数,我建议在调用者开始时执行以下操作:

i=0
for arg in "$@"; do
    echo "arg$i=$arg"
    let ++i
done

## Example of calls to the previous script
#caller.sh '1' "2" 3 "4 4" "5  5"
#arg1=1
#arg2=2
#arg3=3
#arg4=4 4
#arg5=5  5

@Flimm是正确的,无法区分参数
“foo”
foo
,这仅仅是因为在程序接收引号之前,shell会删除引号。您需要的是“$@”(带引号)。

您可以从shell历史记录中获得此信息:

function myhack {
  line=$(history 1)
  line=${line#*  }
  echo "You wrote: $line"
}
alias myhack='myhack #'
正如您所描述的:

$ myhack --args="stuff" * {1..10}    $PATH
You wrote: myhack --args="stuff" * {1..10}    $PATH
然而,引用只是用户告诉shell如何构造程序的参数数组的方式。要求记录用户如何引用他们的论点,就像要求记录用户在钥匙上的力度以及他们当时的穿着一样

要记录明确捕获所有提供参数的shell命令行,不需要任何交互式shell破解:

#!/bin/bash
line=$(printf "%q " "$@")
echo "What you wrote would have been indistinguishable from: $line"

问题是引号在到达echo之前就被解析了。让echo看到它们的一种方法是避开它们:
echo\“hello world\”
。我意识到这并不能解决你的问题。也许解析的变体已经足够好了?您永远无法在命令行上捕获I/O重定向;它们不会中继到被调用的进程。此外,引号等被shell删除,因此被调用的程序永远不会看到它们。因此,被调用的程序无法判断命令行中是否有引号。