我有一个脚本,它运行一系列编号为 001,002,003,004...等的脚本,现在一直到 041,将来会更多 - 这些脚本本身使用一些光标控件来打印进度条和其他状态信息并获取终端的宽度和高度分别为tput cols和tput lines。
在不重写子脚本的情况下,我想在底部保留一行用于外部脚本的总体状态信息。我很好奇是否有办法设置 tput 对行和列的回复。
一定有办法,因为 tmux 实现了它。我认为可能存在环境变量,但我可以看到 tmux 在运行 env 时所做的唯一更改是将 $TERM 设置为屏幕。
任何帮助将不胜感激
从我从在线文档中收集的信息来看,以下内容应该为嵌入的命令部分生成一个子shell {}:
$ bash -c '{ sleep 10; echo "Sleeping process", $$; } & echo $$; '
11237
Sleeping process, 11237
Run Code Online (Sandbox Code Playgroud)
但是,正如您所看到的,在这两种情况下,进程 ID 是相同的。我错过了什么?感谢您的指点。
从这个问题的答案中,我意识到不仅我不太了解“子外壳”的整个概念,而且更一般地说,我不了解fork-ing 和子进程之间的关系。
我曾经认为,当进程X执行 a 时fork,会创建一个新进程Y,其父进程是X,但根据该问题的答案,
[a] subshell 不是一个全新的进程,而是现有进程的一个分支。
这里的含义是“分叉”不是(或不会导致)“一个全新的过程”。
我现在很迷茫,实在是太迷糊了,无法提出一个连贯的问题来直接打消我的迷茫。
然而,我可以提出一个可能间接导致启蒙的问题。
因为,根据zshall(1),$ZDOTDIR/.zshenv每当一个新的实例zsh启动时就会被获取,那么任何$ZDOTDIR/.zshenv导致创建“一个全新的 [zsh] 进程”的命令都会导致无限回归。另一方面,在$ZDOTDIR/.zshenv文件中包含以下任一行不会导致无限回归:
echo $(date; printenv; echo $$) > /dev/null #1
(date; printenv; echo $$) #2
Run Code Online (Sandbox Code Playgroud)
我发现通过上述机制引起无限回归的唯一方法是在文件中包含如下所示的行1$ZDOTDIR/.zshenv:
$SHELL -c 'date; printenv; echo $$' #3
Run Code Online (Sandbox Code Playgroud)
我的问题是:
由于这种行为差异#1,#2上面标记的命令和标记为#3帐户的命令之间有什么区别?
如果获得创建的壳#1和#2被称为“子shell”,那些是什么样所产生的一个 …
假设我有一个脚本,我在其中导出了一个变量,如下所示:
#!/bin/bash
foo(){
eval export one=1
}
foo1(){
eval export two=2
}
(foo)
foo1
echo "one=$one"
echo "two=$two"
Run Code Online (Sandbox Code Playgroud)
但是我得到了以下输出:
root@centos1:~>/tmp/test.sh
one=
two=2
Run Code Online (Sandbox Code Playgroud)
什么可能是我无法看到的价值$one和可以看到的原因$two?
在子 shell 中运行序列命令,如下所示:
(git pull;git rebase develop)&>/dev/null
Run Code Online (Sandbox Code Playgroud)
我认为这会将子 shell 及其创建的所有子进程置于后台,并将控制权返回给用户。
但实际上,终端挂了一段时间,似乎是在等待子shell中的命令完成。
任何人都可以解释为什么会发生这种情况,以及做这种工作的正确方法是什么。
到目前为止,我知道有两种主要方式:
显式:将括号括在命令列表中
隐式:管道中的每个命令
是否有更多的方式,无论是显式还是隐式,在 bash 中创建子shell?
运行命令后
{ sleep 5; } &
Run Code Online (Sandbox Code Playgroud)
输出ps是(输出1)
PID TTY TIME CMD
972 ttys000 0:00.27 -bash
2556 ttys000 0:00.00 -bash
2557 ttys000 0:00.00 sleep 5
Run Code Online (Sandbox Code Playgroud)
而对于
( sleep 5 ) &
Run Code Online (Sandbox Code Playgroud)
出ps是(输出 2)
PID TTY TIME CMD
972 ttys000 0:00.28 -bash
2566 ttys000 0:00.00 sleep 5
Run Code Online (Sandbox Code Playgroud)
()导致子shell环境,我希望在这种情况下为“输出1”,因为它会导致子进程分叉,而我希望{ sleep 5; } &在当前shell中执行时为“输出2” 。这可能看起来是一个愚蠢的问题,但我真的不明白这种行为。
我在这里缺少什么?
说我有这个:
set -e;
(
docker stop notifier-server
docker rm -f notifier-server
exit 1 # explicitly exit with non-zero
) &
wait;
echo 'we are here now'
Run Code Online (Sandbox Code Playgroud)
即使子shell以非零值退出,我们是否总是会到达回声线?我认为是的,因为它是一个后端进程/子shell?
看待这个问题的正确方法是什么?
场地小
\n\n我经常使用子 shell 来执行涉及更改Shell 执行环境的操作,以免影响主 shell。我经常从交互式 shell 中执行此操作,有时也从脚本中执行此操作。
\n\n启用或禁用作业控制当然是这些操作之一,无论出于何种原因,当需要精细控制进程分组时,我一直在随意使用此功能。
\n\n然而,作为 Bash 用户,我注意到这种自由在最新版本中得到了加强:直到 v4.3,作业控制才被允许并在交互式子 shell 中完全工作,但自 v4.4 以来就不再这样了。在那里,它仍然可以在交互式子 shell 中使用,但不能完全工作(见下文)。它在脚本内仍然可以很好地工作,但是,自 v5 以来,至少一个作业控制的特定用例(即 的细粒度处理Ctrl+C)已经更加严格,使其只能从脚本内的子 shell 内进行管理..!
\n\n因此,我开始产生怀疑,因此花了一些时间对一些常见的 shell 进行了示例综合测试,所有这些测试都是在 Ubuntu 19.04 上使用其测试 shell 的库存(和发行版更新)版本执行的。
\n\n一些背景
\n\n我注意到bash, yash, mksh, 和zshdo Honorset -m在子 shell 中,而dash和kshdo 则没有。ksh即使在测试结束时被拦住也很奇怪。
TL; DR:接下来是我刚才所说的漫长的演示会议:
\n\n$ bash -c \'echo start; (set -bm; …Run Code Online (Sandbox Code Playgroud) 该命令df .可以向我们显示我们在哪个设备上。例如,
me@ubuntu1804:~$ df .
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sdb1 61664044 8510340 49991644 15% /home
Run Code Online (Sandbox Code Playgroud)
现在我想得到字符串/dev/sdb1。
我这样试过,但没有用:df . | read a; read a b; echo "$a",这个命令给了我一个空的输出。但df . | (read a; read a b; echo "$a")会按预期工作。
我现在有点困惑。
我知道这(read a; read a b; echo "$a")是一个子shell,但我不知道为什么我必须在这里制作一个子shell。据我了解,x|y会将 的输出重定向x到y. 为什么read a; read a b; echo $a不能获得输入但子外壳可以?
subshell ×10
bash ×5
shell ×3
shell-script ×3
command ×1
fork ×1
gnu-screen ×1
job-control ×1
pipe ×1
process ×1
read ×1
scripting ×1
tmux ×1
variable ×1
zsh ×1