bash: 'map' 函数参数?
bash: 'map' function arguments?
在将列表转发到其他命令之前,通过某种转换(例如连接每个字符串)本质上 'map' 一个包含 bash 个参数的列表的最优雅方法是什么?想到使用 xargs
,但我似乎无法概念化如何执行此操作。
function do_something {
# hypothetically
for arg in "$@"; do
arg="$arg.txt"
done
command "$@"
}
do_something file1 file2 file3
这样的结果就是调用 command file1.txt file2.txt file3.txt
.
你所做的大部分是正确的,除了你需要使用数组来存储新参数:
function do_something {
array=()
for arg in "$@"; do
array+=("$arg.txt")
done
command "${array[@]}"
}
do_something file1 file2 file3
为了"forward"其他命令的参数,有几种方法。试试这个脚本:
printargs() {
echo "Args for :"
shift
for a in "$@"; do
echo " arg: -$a-"
done
}
printargs dolstar $*
printargs dolstarquot "$*"
printargs dolat $@
printargs dolatquot "$@"
并使用测试参数调用它:
./sc.sh 1 2 3
Args for dolstar:
arg: -1-
arg: -2-
arg: -3-
Args for dolstarquot:
arg: -1 2 3-
Args for dolat:
arg: -1-
arg: -2-
arg: -3-
Args for dolatquot:
arg: -1-
arg: -2-
arg: -3-
如果参数包含空格,情况会有所不同:
./sc.sh 1 "2 3"
Args for dolstar:
arg: -1-
arg: -2-
arg: -3-
Args for dolstarquot:
arg: -1 2 3-
Args for dolat:
arg: -1-
arg: -2-
arg: -3-
Args for dolatquot:
arg: -1-
arg: -2 3-
dolatquot "$@" 是唯一正确转发参数的版本。否则,如另一个答案所示,您可以操纵参数并通过数组或单个字符串构造新列表。
您可以对 map
使用以下定义,它类似于许多函数式编程语言(例如 python, haskell)中的定义:
function map
{
local f=""
shift # consume first argument
for arg
do
"$f" "$arg" # assuming `f` prints a single line per call
done
}
以下是您将如何在您的示例中使用它。这里command
可能是本地定义的函数:
function do_something
{
local IFS=$'\n' # only split on newlines when word splitting
result=($(map suffix "$@")) # split into lines and store into array
command "${result[@]}" # call command with mapped arguments.
}
function suffix
{
echo "$@".txt
}
do_something file1 file2 file3
这是另一种写法do_something
。这里 command
必须存在于 $PATH
:
function do_something
{
map suffix "$@" | xargs command # call command with mapped arguments.
}
主要缺点是要在另一个函数中使用结果,您需要弄乱 IFS
以在换行符上拆分,或通过管道输入 xargs;如果您的地图输出包含换行符,那么任何一种方法都将完全失败。
在将列表转发到其他命令之前,通过某种转换(例如连接每个字符串)本质上 'map' 一个包含 bash 个参数的列表的最优雅方法是什么?想到使用 xargs
,但我似乎无法概念化如何执行此操作。
function do_something {
# hypothetically
for arg in "$@"; do
arg="$arg.txt"
done
command "$@"
}
do_something file1 file2 file3
这样的结果就是调用 command file1.txt file2.txt file3.txt
.
你所做的大部分是正确的,除了你需要使用数组来存储新参数:
function do_something {
array=()
for arg in "$@"; do
array+=("$arg.txt")
done
command "${array[@]}"
}
do_something file1 file2 file3
为了"forward"其他命令的参数,有几种方法。试试这个脚本:
printargs() {
echo "Args for :"
shift
for a in "$@"; do
echo " arg: -$a-"
done
}
printargs dolstar $*
printargs dolstarquot "$*"
printargs dolat $@
printargs dolatquot "$@"
并使用测试参数调用它:
./sc.sh 1 2 3
Args for dolstar:
arg: -1-
arg: -2-
arg: -3-
Args for dolstarquot:
arg: -1 2 3-
Args for dolat:
arg: -1-
arg: -2-
arg: -3-
Args for dolatquot:
arg: -1-
arg: -2-
arg: -3-
如果参数包含空格,情况会有所不同:
./sc.sh 1 "2 3"
Args for dolstar:
arg: -1-
arg: -2-
arg: -3-
Args for dolstarquot:
arg: -1 2 3-
Args for dolat:
arg: -1-
arg: -2-
arg: -3-
Args for dolatquot:
arg: -1-
arg: -2 3-
dolatquot "$@" 是唯一正确转发参数的版本。否则,如另一个答案所示,您可以操纵参数并通过数组或单个字符串构造新列表。
您可以对 map
使用以下定义,它类似于许多函数式编程语言(例如 python, haskell)中的定义:
function map
{
local f=""
shift # consume first argument
for arg
do
"$f" "$arg" # assuming `f` prints a single line per call
done
}
以下是您将如何在您的示例中使用它。这里command
可能是本地定义的函数:
function do_something
{
local IFS=$'\n' # only split on newlines when word splitting
result=($(map suffix "$@")) # split into lines and store into array
command "${result[@]}" # call command with mapped arguments.
}
function suffix
{
echo "$@".txt
}
do_something file1 file2 file3
这是另一种写法do_something
。这里 command
必须存在于 $PATH
:
function do_something
{
map suffix "$@" | xargs command # call command with mapped arguments.
}
主要缺点是要在另一个函数中使用结果,您需要弄乱 IFS
以在换行符上拆分,或通过管道输入 xargs;如果您的地图输出包含换行符,那么任何一种方法都将完全失败。