有没有办法将 HEREDOC 用于 Bash 和 Zsh,并且能够使用参数?

non*_*ity 6 bash zsh shell-script here-document

Bash 和 Zsh 的 HEREDOC 似乎像一个文件,而不是字符串,如果我希望做类似的事情

foo() {
    ruby << 'EOF'
        3.times do
            puts "Ruby is getting the argument #{ARGV[0]}"
        end
EOF 
}
Run Code Online (Sandbox Code Playgroud)

有没有办法将参数传递给 Ruby 程序?最好不要将 插入$1到 Ruby 代码中,这就是我使用'EOF'代替 的原因EOF,因为插入到 Ruby 代码中可能会很麻烦。

有一种方法可以将 HEREDOC 用作字符串,方法如下:

foo() {
    ruby -e "$(cat << 'EOF'
        3.times do
            puts "Ruby is getting the argument #{ARGV[0]}"
        end
EOF
)" $1    
}
Run Code Online (Sandbox Code Playgroud)

它有效(虽然有点hacky)。但是有没有一种方法可以使用HEREDOC 的通常方式将其视为文件并能够向Ruby 提供参数?

Sté*_*las 10

在带有 的系统上,您始终可以执行以下操作:/dev/fd/n

foo() {
  ruby /dev/fd/3 "$@" 3<< 'EOF'
    3.times do
      puts "Ruby is getting the argument #{ARGV[0]}"
    end
EOF
}
Run Code Online (Sandbox Code Playgroud)

这里使用 2 以上的 fd,因此您的ruby脚本仍然可以使用 stdin/stdout/stderr 不受影响。

如果您的系统是少数仍然不支持的系统之一,您可以执行以下操作:/dev/fd/n

foo() {
  ruby - "$@" << 'EOF'
    3.times do
      puts "Ruby is getting the argument #{ARGV[0]}"
    end
EOF
}
Run Code Online (Sandbox Code Playgroud)

(其中ruby本身解释-为含义stdin)。

但这意味着ruby内联脚本的标准输入现在是heredoc,因此除非您以其他方式提供该流,否则该脚本将无法通过原始标准输入查询用户。

Heredoc 是 70 年代后期 Bourne shell 附带的一项功能。这是一个重定向操作符,它的意思是将一些文件描述符(0默认情况下也称为 stdin)重定向到一些固定内容。最初,这是通过临时文件实现的,尽管包括 bash5.1+ 在内的一些 shell 使用(有时)管道代替。

另请注意,与 in或in一样,但与 in 不同的是,您确实需要将其标记为选项的结尾,否则,如果以开头,则将其视为 to 的选项。ruby -e code -- arbitrary-argumentsed -e codeperl -e codesh -c codepython -c code--arbitrary-argument-ruby

我们并不需要它,也不是没有预期非选项参数是经过选择或。ruby /dev/fd/3 arbitrary-argumentruby - arbitrary-argument-/dev/fd/3


tha*_*isp 8

您可能想使用这种语法,只需将 ruby​​ 程序包含在单引号中:

#!/bin/sh -

foo() {
    ruby -e '
        3.times do
            puts "Ruby is getting the argument #{ARGV[0]}"
        end
    ' -- "$@"
}

foo test-arg
Run Code Online (Sandbox Code Playgroud)

类似于python -c 'command'orawk ''sh -c 'command'etc. 后跟参数。在引号内,您可以使用代码编写多行文本。(--对于定义选项的结尾很重要,例如对于以下参数以 开头的情况-,另请参阅此答案

这实际上是 ruby​​ 命令的外壳包装器,您可以使用外壳过滤输入、处理输出、调用更多程序等。此外,在这里您可以看到更多关于引用参数的信息,我已替换"$@"为引用所有参数,从shell脚本传递到ruby命令,你也可以使用$1$2等等

当然,单引号需要一些注意。如果可以,请避免它们。使用它们的方法可能不止一种,例如\047\'在两个单引号字符串之间插入。例子:

#!/bin/sh -

foo() {
    ruby -e '
        3.times do
            puts "Ruby is getting the argument #{ARGV[0]}"
        end
    ' -- "$@"
}

foo test-arg
Run Code Online (Sandbox Code Playgroud)

这里有更多关于引用的内容。