【问题标题】:Why does `cd` break redirects by `exec`?为什么`cd`会破坏`exec`的重定向?
【发布时间】:2021-06-16 10:59:24
【问题描述】:

我正在尝试将部分输出从脚本重定向到文件并这样做:

#!/usr/bin/bash
cleanup() {
  echo "Lines in $tmpfile:"
  cat $tmpfile
  rm $tmpfile
}

tmpfile=$(mktemp .tmp.`basename $0`.XXXXXX)
trap cleanup EXIT
for var in one two; do
  echo "$var: Before redirect"
  exec 6>&1           # Save stdout to descriptor #6
  exec >> "$tmpfile"  # Send output to file
  if [ 'a' == 'b' ]; then
    echo "this never happens"
  else
    echo "$var: line in file"
  fi
  exec 1>&6 # Restore stdout
  exec 6>&- # Close descriptor 6
  echo "$var: After redirect"
done

这会产生预期的输出:

$ ./test-working.sh
one: Before redirect
one: After redirect
two: Before redirect
two: After redirect
Lines in .tmp.test-working.sh.c3noO3:
one: line in file
two: line in file

如果我像这样做一个小调整:

$ diff -u test-working.sh test-broken.sh
--- test-working.sh     2021-06-16 12:48:35.852500568 +0200
+++ test-broken.sh      2021-06-16 12:48:35.205483749 +0200
@@ -7,6 +7,7 @@

 tmpfile=$(mktemp .tmp.`basename $0`.XXXXXX)
 trap cleanup EXIT
+cd
 for var in one two; do
   echo "$var: Before redirect"
   exec 6>&1           # Save stdout to descriptor #6
@@ -20,3 +21,4 @@
   exec 6>&- # Close descriptor 6
   echo "$var: After redirect"
 done
+cd -

然后就坏了:

$ ./test-broken.sh
one: Before redirect
one: After redirect
two: Before redirect
two: After redirect
/script/run/path
Lines in .tmp.test-broken.sh.HSgMrS:

使用set -x,您可以清楚地看到echo 在某处写了一些东西:

$ bash -x test-broken.sh
+++ basename test-broken.sh
++ mktemp .tmp.test-broken.sh.XXXXXX
+ tmpfile=.tmp.test-broken.sh.c6mf6c
+ trap cleanup EXIT
+ cd
+ for var in one two
+ echo 'one: Before redirect'
one: Before redirect
+ exec
+ exec
+ '[' a == b ']'
+ echo 'one: line in file'
+ exec
+ exec
+ echo 'one: After redirect'
one: After redirect
+ for var in one two
+ echo 'two: Before redirect'
two: Before redirect
+ exec
+ exec
+ '[' a == b ']'
+ echo 'two: line in file'
+ exec
+ exec
+ echo 'two: After redirect'
two: After redirect
+ cd -
/script/run/path
+ cleanup
+ echo 'Lines in .tmp.test-broken.sh.c6mf6c:'
Lines in .tmp.test-broken.sh.c6mf6c:
+ cat .tmp.test-broken.sh.c6mf6c
+ rm .tmp.test-broken.sh.c6mf6c

但它并没有出现在预期的文件中。我正在努力看看我做错了什么。为什么cd 会破坏重定向?

【问题讨论】:

  • 您正在主目录中创建另一个同名文件并将标准输出重定向到它。你还期待发生什么?请改用mktemp -p '' whatever

标签: bash exec io-redirection cd


【解决方案1】:

正如 cmets 中所指出的,我的代码读取和写入相同的文件名,但使用不同的相对路径。绝对路径修复它:

$ diff -u test-broken.sh test-broken-fixed.sh
--- test-broken.sh      2021-06-16 13:21:30.301815257 +0200
+++ test-broken-fixed.sh        2021-06-16 13:22:03.222670969 +0200
@@ -5,7 +5,7 @@
   rm $tmpfile
 }

-tmpfile="$(mktemp .tmp.`basename $0`.XXXXXX)"
+tmpfile="$PWD/$(mktemp .tmp.`basename $0`.XXXXXX)"
 trap cleanup EXIT
 cd
 for var in one two; do

使用mktemp -p '' filename 也可以,然后文件将位于/tmp

【讨论】:

    猜你喜欢
    • 2011-09-27
    • 1970-01-01
    • 2012-12-15
    • 2015-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    相关资源
    最近更新 更多