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;如果您的地图输出包含换行符,那么任何一种方法都将完全失败。