因此,我希望能够从用户那里获取输入,用户将输入空格分隔的字符串或值,然后逐个检查这些值并将它们转换为我拥有的命令之一所需的格式。我想要这样的东西:例如
用户将收到类似如下的提示:
Specify the package: perl runtime pool tools
我只输入4个字符串。现在对于我的输出我想要这样的东西:
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools
Pkg 基本上根据用户输入的数量增加 1。
这可能吗?我怎样才能在 bash 中实现这一目标?
任何帮助将不胜感激!感谢您的时间!
答案1
首先不提示!提示输入数据很少是一个好主意:很容易犯错误、拼写错误、命令不能重复、不能对文件名使用制表符补全等等。这只会让你的用户和你自己的生活无缘无故地变得更加困难。只需让用户将包名称作为参数传递即可:
#!/bin/bash
packageString="Pkg1=$1"
shift
for (( i=1; i<=$#;i++)); do
packageString+=";Pkg"$((i+1))"=${!i}"
done
echo "$packageString";
使用问题中的输入运行上述脚本会导致:
$ foo.sh perl runtime pool tools
Pkg1=perl;Pkg2=runtime;Pkg3=pool;Pkg4=tools
答案2
我在回响特登斯抗辩不要无缘无故地以交互方式提示用户。在这种情况下,用户可以更轻松地将字符串作为脚本的参数提供,因为它使他们可以选择从 shell 的命令行历史记录中调用命令或使用 shell 的制表符补全、常规编辑功能等。
以下脚本使用单个awk
命令。
该awk
命令将给定的字符串作为其命令行参数,并在循环中单独格式化每个字符串。循环的目的是构建字段记录,每个字段都是某个字符串PkgN=something
,其中N
是整数计数器并且something
是给定字符串之一。
循环结束后,print
输出完整的记录。分配给的分隔OFS
符用于字段之间。
#!/bin/sh
awk -v OFS=, '
BEGIN {
for (i = 1; i < ARGC; ++i) $i = sprintf("Pkg%d=%s", i, ARGV[i])
print
}' "$@"
相同的想法,但使用 shell 循环:
#!/bin/sh
i=0
for pkg do
i=$(( i + 1 ))
set -- "$@" "Pkg$i=$pkg"
shift
done
IFS=,
printf '%s\n' "$*"
这将用新字符串替换每个位置参数(脚本的参数),并以逗号作为分隔符将它们全部打印出来。
如果没有给出参数,这两个脚本都会输出空行。您可以通过在脚本开头测试参数并在没有参数时退出来避免这种情况:
[ "$#" -ne 0 ] || exit
如果不带参数调用脚本,此处完成测试的方式将确保脚本以非零退出状态终止。
测试:
$ ./script perl runtime pool tools
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools
答案3
script.sh
包含以下代码的脚本(在下面的示例中命名)应该会为您提供所描述的输出:
#!/bin/bash
#USER INPUT
read -p "Specify the package: " -a vals
#COUNTER
i=1
#ARRAY ELEMENT LOOP
for v in "${vals[@]}"; do
#Printing output
echo -n "Pkg$i=$v"
#Increment counter and add the comma, or break out of loop if $i==
i=$((i+1))
if [[ $i -le ${#vals[@]} ]]; then
echo -n ","
else
break
fi
done
要从 shell 运行脚本,您需要首先使其可执行 ( chmod
),然后执行它:
chmod +x script.sh
./script.sh
它的输入/输出将如下所示:
Specify the package: perl runtime pool tools
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools
答案4
$ perl -le 'print join ",", map { "Pkg" . ++$i . "=$_" } @ARGV' perl runtime pool tools
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools
map { "Pkg" . ++$i . "=$_" } @ARGV
Pkg
返回一个列表,其中每个元素都是以文字字符串、计数器变量 ( $i
)(在每次循环时自动递增)map
和文字符号为前缀的命令行参数之一=
。perldoc -f map
有关其工作原理的详细信息,请参阅。
该列表以逗号作为分隔符连接,然后打印。看perldoc -f join
。
该-l
选项启用自动行结束处理。对于此脚本,由于没有要处理的标准输入,这意味着每个print
语句都会自动输出换行符(通常,perlprint
不会输出换行符,除非您显式包含它)。查看man perlrun
并搜索-l\[octnum\]
.
如果您想首先接受用户输入(正如其他人指出的那样,不建议这样做,因为这对用户来说非常烦人且不方便),那么您可以使用以下方法来做到这一点:
#!/bin/bash
# read the user input into array variable "$input"
read -p "Specify the package: " -r -a input
# now pass the array to the perl one-liner
perl -le 'print join ",", map { "Pkg" . ++$i . "=$_" } @ARGV' -- "${input[@]}"
这--
可以防止 perl 将任何用户输入解释为选项,以防万一用户意外(或恶意)输入类似 perl 命令行选项的内容 - 例如-e ';system("rm -rf /");'
。永远不要相信用户提供的输入。
并且,像往常一样,如果您需要将 perl 脚本的输出捕获到另一个 shell 变量中,请使用命令替换:
var=$(perl -le 'print join ",", map { "Pkg" . ++$i . "=$_" } @ARGV' -- "${input[@]}")
printf "%s\n" "$var"