Flu*_*lux 53 bash shell-script
假设一个程序cook接受一个参数:包含要烹饪的食物配方的文本文件的路径名。假设我想从bash脚本中调用这个程序,还假设我已经在一个字符串变量中拥有了配方:
#!/bin/bash
the_recipe="$(cat << EOF
wash cucumbers
wash knife
slice cucumbers
EOF
)"
cook ... # What should I do here? It expects a file, but I only have a string.
Run Code Online (Sandbox Code Playgroud)
当需要文件名参数时,如何将配方传递给命令?
我想创建一个临时文件只是为了传递文件,但我想知道是否有其他方法可以解决这个问题。
wur*_*tel 55
您可以使用/dev/stdin代表标准输入的“假”文件名。
所以执行这个:
echo "$the_recipe" | cook /dev/stdin
Run Code Online (Sandbox Code Playgroud)
echo 命令和管道将指定变量的内容发送到下一个命令cook的标准输入,然后打开标准输入(作为单独的文件描述符)并读取它。
Ini*_*ian 45
使用bashshell的进程替换功能的另一种方法是在/tmp或下创建 FIFO /var/tmp,或者使用命名文件描述符 ( /dev/fd/*),具体取决于操作系统。替换语法( <(cmd)) 被FIFO 或FD 的名称替换,并且其中的命令在后台运行。
cook <(printf '%s\n' "${the_recipe}")
Run Code Online (Sandbox Code Playgroud)
该命令cook现在读取变量的内容,就像它在文件中可用一样。
这也可以用于多个输入文件:
cook <(printf '%s\n' "${the_1st_recipe}") <(printf '%s\n' "${the_2nd_recipe}")
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 24
这取决于应用程序的功能。它可能会也可能不会坚持一个命名文件,它可能会也可能不会坚持一个可查找的文件。
一些应用程序只是从任何地方读取输入。通常,它们默认从标准输入读取。如果您有字符串形式的数据,并且希望将其传递给应用程序的标准输入,则有几种方法。您可以通过管道传递信息:
printf '%s' "$the_recipe" | cook # passes $the_recipe exactly
printf '%s\n' "$the_recipe" | cook # passes $the_recipe plus a final newline
Run Code Online (Sandbox Code Playgroud)
不要echo在这里使用,因为根据 shell,它可能会破坏反斜杠。
如果应用程序坚持使用文件参数,它可能接受-表示标准输入。这是一个普遍的惯例,但并不系统。
printf '%s\n' "$the_recipe" | cook -
Run Code Online (Sandbox Code Playgroud)
如果应用程序需要实际的文件名,则传递/dev/stdin到表示标准输入。
printf '%s\n' "$the_recipe" | cook /dev/stdin
Run Code Online (Sandbox Code Playgroud)
对于某些应用程序,即使这还不够:它们需要具有特定属性的文件名,例如具有给定扩展名,或者它们需要在创建临时文件的可写目录中的文件名。在这种情况下,您通常需要一个临时文件,尽管有时命名管道就足够了。
可以为管道命名。我提到这一点是为了完整性,但这很少是最方便的方式。它确实避免了在磁盘上获取数据。如果应用程序需要一个对名称有限制的文件,但不需要该文件是可查找的,则它是合适的。
mkfifo named.pipe
printf '%s\n' "$the_recipe" >named.pipe & writer=$!
cook named.pipe
rm named.pipe
wait "$writer"
Run Code Online (Sandbox Code Playgroud)
(省略错误检查。)
如果应用程序需要一个可搜索的文件,你需要创建一个临时文件。可查找文件是应用程序可以来回访问、一次读取任意部分的文件。管道不允许这样做:它需要从头到尾依次读取,不能倒退。
Bash、ksh 和 zsh 有一种方便的语法,可以通过临时文件将字符串作为输入传递。请注意,它们总是在字符串后附加一个换行符(即使已经有一个换行符)。
cook <<<"$the_recipe"
Run Code Online (Sandbox Code Playgroud)
使用其他shell,或者如果要控制哪个目录包含临时文件,则需要手动创建临时文件。大多数 unices 提供了一个mktemp实用程序来安全地创建临时文件。(永远不要使用类似的东西!它允许其他程序,甚至以其他用户身份运行,劫持文件。)这是一个创建临时文件并在中断时负责删除它的脚本。… >/tmp/temp.$$
tmp=
trap 'rm -f "$tmp"' EXIT
trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
tmp=$(mktemp)
printf '%s\n' "$the_recipe" >"$tmp"
cook "$tmp"
Run Code Online (Sandbox Code Playgroud)
要选择创建临时文件的位置,请TMPDIR为mktemp调用设置环境变量。例如,要在当前目录而不是临时文件的默认位置创建临时文件:
tmp=$(TMPDIR="$PWD" mktemp)
Run Code Online (Sandbox Code Playgroud)
(使用$PWD而不是.为您提供绝对文件名,这意味着您可以安全地调用cd您的脚本,而不必担心$tmp不再指定相同的文件。)
如果应用程序需要具有特定扩展名的文件名,则需要创建一个临时目录并在那里创建一个文件。要创建临时目录,请使用mktemp -d. TMPDIR如果要控制创建临时目录的位置,请再次设置环境变量。
tmp=
trap 'rm -rf "$tmp"' EXIT
trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
tmp=$(mktemp -d)
printf '%s\n' "$the_recipe" >"$tmp/myfile.ext"
cook "$tmp/myfile.ext"
Run Code Online (Sandbox Code Playgroud)
在尝试更复杂的解决方案之前,请务必检查您的版本是否cook支持参数-(破折号)作为文件名。如果支持此约定,它会告诉您cook从标准输入中读取,如下所示:
echo "$the_recipe" | cook -
Run Code Online (Sandbox Code Playgroud)
或者
cook - <<<"$the_recipe"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22557 次 |
| 最近记录: |