为什么`read -r` 仍然只得到每行的第一个单词?

der*_*ugo 3 bash scripts

这个问题与我在这里的旧问题有关。

在我终于找到了如何将 git 的输出绕过到函数中之后,我现在遇到了另一个问题。使用

git clone --progress XYZ &> git_clone.file
Run Code Online (Sandbox Code Playgroud)

按预期写入

Cloning to 'someRepository' ...
remote: Counting objects: 2618, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 2618 (delta 2), reused 12 (delta 1), pack-reused 2603
Received objects: 100% (2618/2618), 258.95 MiB | 4.39 MiB/s, Done.
Resolving Differences auf: 100% (1058/1058), Done.
Check Connectivity ... Done.
Run Code Online (Sandbox Code Playgroud)

进入git_clone.file

现在我不想将输出重定向到文件而是重定向到函数,所以我使用

function PrintInfo(){
    tput el
    echo $1
    <Print ProgressBar> 
    #For further details about this see 
    # https://askubuntu.com/questions/988403/bash-pass-command-output-to-function-in-realtime
}

git clone --progress XYZ |& {
    while read -r line
    do
        PrintInfo $line
    done
}
Run Code Online (Sandbox Code Playgroud)

现在我希望得到

Cloning to 'someRepository' ...
remote: Counting objects: 2618, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 2618 (delta 2), reused 12 (delta 1), pack-reused 2603
Received objects: 100% (2618/2618), 258.95 MiB | 4.39 MiB/s, Done.
Resolving Differences auf: 100% (1058/1058), Done.
Check Connectivity ... Done.
Run Code Online (Sandbox Code Playgroud)

我的其他问题中所述,逐行打印并在底部打印我的进度条。但相反,我只得到

Cloning
remote:
remote:
Received
...
Run Code Online (Sandbox Code Playgroud)

等等。我已经尝试了所有形式的IFS喜欢

... while IFS= read -r ...

... while IFS='' read -r ...

... while IFS="\n" read -r ...
Run Code Online (Sandbox Code Playgroud)

但他们都没有解决这个问题。

如何读取输出的完整行?

Joh*_*024 7

问题是分。要解决它,请替换:

PrintInfo $line
Run Code Online (Sandbox Code Playgroud)

和:

PrintInfo "$line"
Run Code Online (Sandbox Code Playgroud)

解释

考虑:

PrintInfo $line
Run Code Online (Sandbox Code Playgroud)

在执行之前,PrintInfoshell 将扩展$line并执行分词路径名扩展

让我们举一个简单的例子,从定义一个函数开始:

$ PrintInfo() { echo "1=$1 2=$2 3=$3"; }
Run Code Online (Sandbox Code Playgroud)

现在,让我们执行函数:

$ line="one two three"
$ PrintInfo $line
1=one 2=two 3=three
Run Code Online (Sandbox Code Playgroud)

在上面,分导致PrintInfo看到三个参数。

如果您只想PrintInfo查看一个参数,请使用:

$ PrintInfo "$line"
1=one two three 2= 3=
Run Code Online (Sandbox Code Playgroud)

路径名扩展也是一个潜在的问题。考虑一个包含这些文件的目录:

$ ls
file1  file2  file3
Run Code Online (Sandbox Code Playgroud)

现在,让我们PrintInfo再次运行我们的版本:

$ line='file?'
$ PrintInfo $line
1=file1 2=file2 3=file3
Run Code Online (Sandbox Code Playgroud)

因为?是一个有效的 glob 字符,所以 shell 会file?用文件名替换。为了防止这种意外,请使用双引号:

$ PrintInfo "$line"
1=file? 2= 3=
Run Code Online (Sandbox Code Playgroud)

概括

除非您明确需要分路径名扩展,否则shell 变量应始终在双引号内