![如何在 bash 脚本文件中参数化我的命令?](https://linux22.com/image/168700/%E5%A6%82%E4%BD%95%E5%9C%A8%20bash%20%E8%84%9A%E6%9C%AC%E6%96%87%E4%BB%B6%E4%B8%AD%E5%8F%82%E6%95%B0%E5%8C%96%E6%88%91%E7%9A%84%E5%91%BD%E4%BB%A4%EF%BC%9F.png)
编辑——不使用 bash
$1
变量。示例是使用字段指示符:$1
、$2
、$3
是awk
输入记录字段不幸的是我太快地完成了示例并且混淆了示例。
我相信这是一个普遍问题。我正在使用它awk
作为演示工具。目的是将 ( awk
) 脚本参数暗示到awk
(或任何工具)命令中。
我们使用从 STDIN 到 as 提供的字段来awk
生成结果。标识符$1
, $2
,$3
是awk
STDIN 流中的字段。
所需的解决方案 A(首选概念),例如......
#!/bin/bash -f
# script: blue.sh
#
awk -e '{ print $1 " and " $2 " silly example" ;}'
#
以及所需的输出:
$ echo "red blue yellow" > ./blue.sh
red and blue silly example
$
或许可以考虑替代方案 B:
#!/bin/bash -f
# script: green.sh
#
wrk="awk -e '{ print \$3 \" and \" \$2 \" variable example\" ;}' "
#
echo "work is:"
echo $wrk
echo
$wrk
以及所需的输出:
$ echo "red blue yellow" > ./green.sh
wrk is:
awk -e '{ print $3 " and " $2 " variable example" ;}'
yellow and blue variable example
$
问题出在-e
表达式的引用上。
有没有办法实现这些例子?
答案1
这可能是“我们如何运行存储在变量中的命令?”,但我会针对您的具体情况回答它,因为它有多个部分:
- 将命令存储在变量中并使用该变量运行它。
- 将数据传递到
awk
.
“变量中的运行命令”位
以下是脚本的替代实现的建议:
#!/bin/bash
wrk=( awk -v a="$3" -v b="$2"
'BEGIN { printf "%s and %s variable example\n", a, b }' )
awk -v a="$1" -v b="$2" 'BEGIN { printf "%s and %s silly example\n", a, b }'
printf 'wrk is: %s\n' "${wrk[*]}"
"${wrk[@]}"
运行这个:
$ ./blue.sh "red" "blue" "yellow"
red and blue silly example
wrk is: awk -v a=yellow -v b=blue BEGIN { printf "%s and %s variable example\n", a, b }
yellow and blue variable example
我所做的是将awk
命令存储在大批而不是在字符串中。这确保了数组的每个单独的元素都可以被正确引用,同时仍然保持为单独的元素,与数组的其他部分分开。例如,awk
开头的单词是与数组中最后一个条目(整个awk
代码)分开的一个单词。
用作命令时"${wrk[@]}"
,数组的每个元素都用作单独的命令行参数(第一个元素是命令)。扩展的引用"${wrk[@]}"
确保每个元素都被单独引用(使用${wrk[@]}
将不起作用)。
这就是在变量中存储和运行命令的方式,即使用数组并确保正确引用数组元素和数组的扩展。
对于printf
shell 脚本中的调用,我使用"${wrk[*]}"
从数组生成单个字符串wrk
(默认情况下所有元素均以空格分隔)。您会注意到,这不会保留对各个元素的任何引用,这是预期的,因为 shell 在创建数组时删除了这些元素(就像在执行类似操作时删除引号一样a='hello world'
)。
要查看 的每个单独元素wrk
,请使用类似的内容printf 'element: "%s"\n' "${wrk[@]}"
。这将输出
element: "awk"
element: "-v"
element: "a=yellow"
element: "-v"
element: "b=blue"
element: "BEGIN { printf "%s and %s variable example\n", a, b }"
在这种特殊情况下,根据您的需要,您还可以使用 shell 函数:
#!/bin/bash
wrk () {
awk -v a="$1" -v b="$2" 'BEGIN { printf "%s and %s variable example\n", a, b }'
}
awk -v a="$1" -v b="$2" 'BEGIN { printf "%s and %s silly example\n", a, b }'
wrk "$3" "$2"
请注意,函数中的$1
and$2
指的是函数的第一个和第二个参数,而不是脚本的。
运行这个:
$ ./blue.sh "red" "blue" "yellow"
red and blue silly example
yellow and blue variable example
-特定awk
位
为了将数据传递到awk
我使用的命令行上-v
初始化awk
变量awk
。这比通过 shell 扩展将变量注入awk
代码更好,因为这样做可能允许用户注入可执行代码而不仅仅是数据(例如,通过简单地$3
包含 a;
和一些代码)。awk
看 ”awk 中的命令行参数“ 和这个网站上有类似的问题了解更多相关信息。
您还可以awk
使用环境变量传递数据:
a=$3 b=$2 awk 'BEGIN { printf "%s and %s variable example\n", ENVIRON["a"], ENVIRON["b"] }' )
或者,
export a="$3"
export b="$2"
awk 'BEGIN { printf "%s and %s variable example\n", ENVIRON["a"], ENVIRON["b"] }' )
我还在awk
单个BEGIN
块中执行代码,因为标准输入上没有可读取的输入。
答案2
我找到了一个解决方案,尽管结果与最初的设想有很大不同。我无法找到一种方法来扩展bash
命令中的 -script 变量,因此必须“构造”它。事实证明,xargs
由于与 shell 想要如何做它的事情有关的几个原因,这是不合适的。
我将介绍一个运行示例,然后介绍代码并描述发生的情况/情况。我用诸如“# (2)”之类的标签标记了要讨论的区域。
例子:
输入...
$ svn status -qu ..
M 28637 /src/line.h
M 28637 /src/line.cpp
* 28637 /testing/CheckWindows.py
加工...
重复脚本有两个参数:
- 要在输入列表上执行的模板或一个或多个命令
- 一些
awk
过滤输入流的命令
命令行:
svn status -qu .. | repeat \
'cp -v $ff /mnt/testhost/testarea/r02/$ff' \
"{ if( $1 == "M" ){ print $3; } }"
输出...
'/src/line.h' -> '/mnt/testhost/testarea/r02/src/line.h'
'/src/line.cpp' -> '/mnt/testhost/testarea/r02/src/line.cpp'
发生了什么?
- 仅将本地修改的文件复制到
r02/testarea
- 显然过滤可以是任何东西
- 的目的
repeat
是在输入的过滤列表上重复一组命令
带注释的代码:
#!/bin/bash
# repeat.bash
function repeat
{
local -a actions=()
local DELIMITER=";"
local filter="${2}"
local cmd=""
local wrk="${1}${DELIMITER}" # (1) Template
local str=""
while [[ $wrk ]] # (2) Split-up individual commands
do
str="${wrk%%"${DELIMITER}"*}"
actions+=( "${str}" )
wrk="${wrk#*"${DELIMITER}"}"
done
echo "actions: " # (3) Debugging code
for action in "${actions[@]}"
do
echo " => \"${action}\"."
done
echo "filter => '${filter}'."
ex="${filter}" # (4) Awk instructions to
# process input stream
for ff in $(awk -e "${ex}") # (5) .
do
for action in "${actions[@]}" # (6) .
do
cmd="${action//\$\{ff\}/${ff}}" # (7) .
cmd="${cmd//\$ff/${ff}}"
${cmd} # (8) .
done
done
return
}
repeat "${@:1}" # (9) .
笔记:
- Arg
$1
是命令模板。
*末尾添加额外的分隔符以供稍后解析 $1
通常是多个命令。将输入参数拆分为单独的分号分隔的命令字符串。- 打印参数进行确认。
- 将过滤器加载到
ex
变量中。
* 在此示例中ex
,仅将过滤器作为 传递$2
。 - 循环过滤后的输入行生成的每个字符串。
*ex
成为awk
作为选择/生成过滤器执行的命令。 - 循环所有
action
命令模板。 - 扩展
$ff
命令字符串${ff}
中的语法action
。 - 为每个文件执行每个生成的命令行:
$ff
. - 调用该函数来执行脚本。
当它变成撅嘴时,这变得非常不同,因为不可能直接将参数注入到awk
或 模板字符串中。然而,解决方法并不太不方便,并且展示了它是如何在没有神秘扩展等的情况下工作的。
我相信这个想法是有用的。现在我有了一个工作片段,我发现它非常方便。