【问题标题】:Puzzling csh redirect behaviour令人费解的 csh 重定向行为
【发布时间】:2014-12-04 11:26:25
【问题描述】:

我在使用输出重定向时发现了 csh 的这种非常奇怪的行为。 我有以下脚本:

#! /bin/csh
set dirs = "."
set files = "`find "'"$dirs"'" -type f |& grep -v '^find: '`"
echo "-----------WITH &-----------------------"
echo "ARRAY:" $files
echo "FIRST ELEMENT FROM ARRAY1:" $files[1]

set files2 = "`find "'"$dirs"'" -type f`"
echo "------------WITHOUT &-----------------------"
echo "ARRAY2" $files2
echo "FIRST ELEMENT SECOND ARRAY" $files2[1]

现在,如果您运行它,一切正常。结果是:

-----------WITH &-----------------------
ARRAY: ./.netscape/preferences.js ...
FIRST ELEMENT FROM ARRAY1: ./.netscape/preferences.js
------------WITHOUT &-----------------------
ARRAY2 ./.netscape/preferences.js ...
FIRST ELEMENT SECOND ARRAY ./.netscape/preferences.js

但是当我像这样运行它时 csh -x test.csh (它是较大脚本的一部分,所以我必须以某种方式对其进行调试)我得到这个:

set dirs = .
set files = `find "$dirs" -type f |& grep -v '^find: '`
grep -v ^find: 
echo -----------WITH &-----------------------
-----------WITH &-----------------------
echo ARRAY: find . -type f ./.netscape/preferences.js ...
ARRAY: find . -type f ./.netscape/preferences.js ...
echo FIRST ELEMENT FROM ARRAY1: find . -type f
FIRST ELEMENT FROM ARRAY1: find . -type f               <----WHY?
set files2 = `find "$dirs" -type f`
find . -type f
echo ------------WITHOUT &-----------------------
------------WITHOUT &-----------------------
echo ARRAY2 ./.netscape/preferences.js ...
ARRAY2 ./.netscape/preferences.js ...
echo FIRST ELEMENT SECOND ARRAY ./.netscape/preferences.js
FIRST ELEMENT SECOND ARRAY ./.netscape/preferences.js

现在,在调试时这会破坏脚本。我觉得这种行为很令人费解。有人能解释一下为什么会发生这种情况以及如何避免吗?

(不要发布我不应该使用 csh 的无用 cmets,这是垃圾。我知道。但我的大学有点强迫我使用它。)

编辑:我按照 John C 的建议做了所有事情。我的输出不同。

bash2-2.05a$ csh -x test.csh 2>catch_stderr
-----------WITH &-----------------------
ARRAY: find . -type f ./test.csh ./ff.csh ./ff ./catch_stderr
FIRST ELEMENT FROM ARRAY1: find . -type f
------------WITHOUT &-----------------------
ARRAY2 ./test.csh ./ff.csh ./ff ./catch_stderr
FIRST ELEMENT SECOND ARRAY ./test.csh

bash2-2.05a$ cat catch_stderr 
set dirs = .
set files = `find "$dirs" -type f |& grep -v '^find: '`
grep -v ^find: 
echo -----------WITH &-----------------------
echo ARRAY: find . -type f ./test.csh ./ff.csh ./ff ./catch_stderr
echo FIRST ELEMENT FROM ARRAY1: find . -type f
set files2 = `find "$dirs" -type f`
find . -type f
echo ------------WITHOUT &-----------------------
echo ARRAY2 ./test.csh ./ff.csh ./ff ./catch_stderr
echo FIRST ELEMENT SECOND ARRAY ./test.csh

【问题讨论】:

  • 哪所大学?他们实际上是在强迫您使用它,还是只是将其作为默认的交互式 shell 提供?
  • 嗯,他们给了我们两个选择,使用 CSH 或一些古老的 BASH 版本。但是,如果您选择 bash,您就只能靠自己了,因为讲座和练习中的每个示例都在 csh 中进行了解释。我宁愿不命名我的大学。
  • -x 将其输出发送到 stderr。我认为您只是看到 stdout 和 stderr 有点混乱。

标签: unix csh


【解决方案1】:

当您运行 csh -x 时,它会将每个命令回显到 stderr。 如果你打开 -x 并像这样运行你的脚本 ....

>sh
sh-3.2$ csh -x test.csh 2>catch_stderr
-----------WITH &-----------------------
ARRAY: ./ff ./ff.csh ./test.csh
FIRST ELEMENT FROM ARRAY1: ./ff
------------WITHOUT &-----------------------
ARRAY2 ./ff ./ff.csh ./test.csh
FIRST ELEMENT SECOND ARRAY ./ff

sh-3.2$ cat catch_stderr
set dirs = .
set files = `find "$dirs" -type f |& grep -v '^find: '`
find . -type f
grep -v ^find:
echo -----------WITH &-----------------------
echo ARRAY: ./ff ./ff.csh ./test.csh
echo FIRST ELEMENT FROM ARRAY1: ./ff
set files2 = `find "$dirs" -type f`
find . -type f
echo ------------WITHOUT &-----------------------
echo ARRAY2 ./ff ./ff.csh ./test.csh
echo FIRST ELEMENT SECOND ARRAY ./ff

(将 stderr 重定向到文件)它的行为方式与没有 -x 时的行为方式相同。 然后您可以查看文件catch_stderr 以查看跟踪信息。 当他们俩一起出来时,他们可以互相混淆一点。

【讨论】:

  • 如果我错了,请纠正我。你是说如果我运行csh -x script.csh 2&gt;catch_stderr 它应该在catch_stderr 中给我与运行csh script.csh 相同的输出,对吗?因为如果我这样做,它仍然会将 find 作为 catch_stderr 中该数组中的第一个值回显。
  • 嗯,看起来 csh 不允许您进行 stderr 重定向。尝试先启动一个 bash shell,然后按照我的解释运行你的脚本,然后你会看到我试图解释的效果。 csh -x 在运行之前回显每个命令。当您在一行中有多个命令时,它会在单独的行中回显每个单独的命令。这一切都与脚本的常规标准输出混淆了。
  • 我确实尝试过,但没有同样的结果。让我们假设在两个回声之后我将添加echo head -n 1 &lt; find . -type f (有子shell引号但markdown将其解释为代码)如果它真的只是stdin和stderr的混乱输出,我应该在这两种情况下看到第一行文件。但我仍然得到find: No such file or directory.
  • 我的意思是 stdout 和 stderr 的输出混乱,抱歉打错了。
  • 我所做的一切都和你一样。我编辑了我的问题并添加了输出。
【解决方案2】:

变量 -x 也适用于子shell。

所以当 subshel​​l `find "'"$dirs"'" -type f |&amp; grep -v '^find: '` 被执行时,它会在 stderr 上回显find . -type f(这不是 2> 不知道为什么,但在我的情况下不是这样)然后执行它,但是 |& 结合了 stderr 和 stdout这个组合在脚本中被替换。所以find . -type f 最终成为数组 $files 中的第一个元素。

解决方法是在``csh中使用|&时要非常小心,csh非常棘手。

John C 也是对的。这实际上为我指明了正确的方向。所以我赞成他的回答。他的 bash 可能会在 subshel​​l 中捕获输出,所以我认为这两种输出都可能出现。他的输出肯定是想要的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2018-07-02
    • 2020-06-19
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多