3

在我尝试的一堆语言中,函数可以返回相当多类型的值(整数、字符串、各种对象、返回函数的函数等),但在 bash 中,似乎唯一允许的类型是 int,它不应该由其他函数使用,而是由 shell 本身使用来了解是否一切正常(返回 0),或者是否发生了某些错误,在这种情况下,返回的值是错误代码。

例如,假设您要编写一个函数,该函数希望将某些内容返回给另一个函数。你应该怎么做?

假设您要编写一个 findvideos 函数,该函数返回在特定文件夹(及其子文件夹)中找到的每个视频。你想在另一个函数中使用那个函数的结果,你会怎么做?通过回声和管道?

我在写一个像这样的小脚本时被困住了:

function firefoxcache {
    cache_dir=$1
    videos_dir=$2
    videos=$(findallvideos $videos_dir)
    for video in $videos; do
    echo cp $video $videos_dir/$(basename $video).flv
    done;
}

function findallvideos {
    videos=$(find $1 -exec file {} \; | grep -i $VIDEOS_REGX | cut -f1 -d:)
    #echo $videos
    return videos
}   

编辑

在 Stackers 的帮助下,这是工作代码(减去愚蠢的双斜线问题):

#!/usr/bin/env bash
function firefoxcache {
cache_dir=$1
videos_dir=$2
echo "$cache_dir", "$videos_dir"
echo
for video in $(findallvideos $cache_dir); do
echo cp $video $videos_dir/$(basename $video).flv
cp $video $videos_dir/$(basename $video).flv
done;
}

function findallvideos {
#echo findallvideos "$1"
for video in $(find $1 -exec file {} \; | grep -i $VIDEOS_REGX | cut -f1 -d:); do
echo $video;
done;
}

firefoxcache $1 $2

# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/B6/6AB61d01 VIDEOS//6AB61d01.flv
# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/28/A3524d01 VIDEOS//A3524d01.flv
# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/D2/29D4Ad01 VIDEOS//29D4Ad01.flv
# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/A1/15D75d01 VIDEOS//15D75d01.flv
# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/A3/2C971d01 VIDEOS//2C971d01.flv
# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/7E/E17D8d01 VIDEOS//E17D8d01.flv
# cp /home/chaouche/.cache/mozilla/firefox/qmkhe4mr.default/Cache/4/AC/5295Dd01 VIDEOS//5295Dd01.flv
4

3 回答 3

3

Bash(和其他 shell)正在使用流来传递值。您引用的返回值与异常有关,而不是与返回值有关。如果返回值 ≠ 0,则其语义通常是发生了错误,调用者不应继续,就好像什么都没发生一样。

另一方面,如果您想返回一个值,则调用的函数、脚本、子进程,以及应该将要返回的值打印stdout. 然后调用者可以捕获该输出并使用它:

square() {
  echo $[ $1 * $1 ]
}

a=4
b=$(square $a)
echo "$a squared is $b"

stdout是执行该操作的主要流程;但是,您也可以使用其他流stderr;因此 shell 可以“返回”多个值。

当然,还有其他方面,例如子进程不一定要终止父进程才能读取并根据其输出采取行动。但我认为这有点超出你的问题的范围。

关于您的具体用例,您必须找到如何通过字节流传输值列表的古老问题的解决方案。一种解决方案是使用Unix 工具的print0选项。find它打印文件名,每个文件名都有一个终止零字节(这是少数几个不能出现在 Unix 路径中的字符之一)。阅读器进程当然必须期待这种格式。例如,您可以使用该选项-0xargs

在您的情况下,我将使用循环使用readthen:

function findallfiles {
    find "$1" -print0
}

function findallvideos {
    findallfiles | while IFS='' read -d $'\0' f
      do
        [[ "$(file -b "$f")" =~ "$VIDEOS_REGX" ]] && printf "%s\0" "$f"
      done
}

function firefoxcache {
  cache_dir=$1
  videos_dir=$2
  findallvideos "$videos_dir" | while IFS='' read -d $'\0' video
    do
      echo cp "$video" "$videos_dir/$(basename "$video").flv"
    done
}
于 2013-10-22T13:02:53.413 回答
2

Shell 脚本只能从函数类型返回整数值。如果要从它们输出字符串,则必须回显该字符串,然后在分配给变量的子shell中捕获该输出。

例如

function foo()
{
    if [ "$1" = "hello" ] ; then
        echo "world";
        return 0;
    fi
    return 1;
}

a=$(foo "hello"); # a = world
echo $?;  # prints 0 - return values and exit status's are always assigned here.

a=$(foo); # a = empty string
echo $?;  # prints 1.
于 2013-10-22T13:05:44.137 回答
1

So for example, suppose you want to write a function that want to return something to another function. How should you do it ?

通过在函数的标准输出上写一些东西,让调用者函数捕获输出。

例子:

function foo () {
    echo "hello"
}

function fooCaller() {
    ret=$(foo)
    [[ "$ret" == "hello" ]] && echo "hello returned from function foo()"
}
于 2013-10-22T12:57:08.960 回答