考虑以下命令:
seq 5 | grep $(tail -n1) <(seq 9)
Run Code Online (Sandbox Code Playgroud)
在zsh1 中运行时:
tail: error reading 'standard input': Input/output error
Run Code Online (Sandbox Code Playgroud)
现在在 中运行相同的bash,它输出:
5
Run Code Online (Sandbox Code Playgroud)
好的。如评论中所述,命令替换$(tail -n1)继承stdin自其父级。但为什么不发生这种情况zsh呢?
这是zsh唯一的事情还是其他 shell 也会做的事情?它在哪里记录?
现在,如果我通过zsh -c以下方式运行相同的命令:
zsh -c 'seq 5 | grep $(tail -n1) <(seq 9)'
Run Code Online (Sandbox Code Playgroud)
而不是打印相同的错误消息,它会在之后停止tail -n1并等待用户输入,所以如果我输入
19
2
4
Run Code Online (Sandbox Code Playgroud)
然后点击Ctrl+ D,它打印
4
Run Code Online (Sandbox Code Playgroud)
这里发生了什么 ?
1:这是与zsh 5.3.1on archlinux,如果重要的话。
我写了一个简单的脚本
#!/bin/bash -x
selentry=`ls -l / | sort ; ts=${PIPESTATUS[0]}`
echo $ts
Run Code Online (Sandbox Code Playgroud)
但 $ts 什么也没显示。如何显示 $ts 变量,或者如何从变量中的命令获取退出状态代码?
selentry=`ls -l / | sort`
Run Code Online (Sandbox Code Playgroud) 我想实现类似这个Q/A 的东西,但是对于一个子外壳。这是我正在尝试的最小示例:
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)
echo subshell done
Run Code Online (Sandbox Code Playgroud)
我怎样才能让它只subshell done返回而不是:
./test.sh: line 4: 5439 Terminated ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done
Run Code Online (Sandbox Code Playgroud)
编辑:我在这里的术语可能是错误的,通过子外壳我的意思是第一组括号内的过程。
更新:
我想发布来自实际程序的片段以供上下文,上面是一个简化:
# If subshell below if killed or returns error connected variable won't be set
(if [ -n "$2" ];then
# code to setup wpa configurations here
# If wifi key is wrong kill subshell …Run Code Online (Sandbox Code Playgroud) $(sleep 5) &
echo $!
sleep 1
echo "done"
Run Code Online (Sandbox Code Playgroud)
以上输出:
$ ./test.sh
7483
done
Run Code Online (Sandbox Code Playgroud)
但是,如果我在中搜索sleep,ps aux我会看到:
ps aux | rg sleep
chris 7484 0.0 0.0 132788 1432 pts/6 S+ 12:10 0:00 sleep 1
chris 7485 0.0 0.0 132788 1432 pts/6 S+ 12:10 0:00 sleep 5
chris 7519 0.0 0.0 10376 5744 pts/7 S+ 12:10 0:00 rg --no-ignore-vcs sleep
Run Code Online (Sandbox Code Playgroud)
sleep 5 进程7485不是7483脚本的输出。这种行为的原因是什么?
想象一下我们有一个很长的命令sleep 10(例如)。我们想在另一台服务器上使用 python(paramiko特定的 ssh 库)执行它。
我需要一个 1 行命令来启动命令,打印命令的 PID,然后等待它完成并最终返回命令的退出状态。
到目前为止我尝试过的:
bash -c "echo $BASHPID ; exec sleep 10" ; echo $?
Run Code Online (Sandbox Code Playgroud)
这将打印 shell 的 PID,然后在长命令上调用 exec,然后等待并打印退出状态。问题是$BASHPID打印外部 bash shell 的 PID(可能表明调用bash -c cmd实际上并没有产生一个全新的 shell?)。
如果我在三行中调用上述命令,它就可以工作。
bash
echo $BASHPID ; exec sleep 10
echo $?
Run Code Online (Sandbox Code Playgroud)
任何使用 subshell 的尝试也对我不起作用。
echo $(echo $BASHPID ; exec sleep 10) ; echo $?
Run Code Online (Sandbox Code Playgroud)
这是可行的,但是子shell 将其所有输出管道传送到echo,并且echo 一次打印所有输出,这意味着$BASHPID直到睡眠完成后才会打印。PID 必须立即打印。
当我执行以下命令时:
#!/bin/bash
while IFS= read -r -d '' file; do
files+=$file
done < <(find -type f -name '*.c' -print0)
echo "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
我没有得到与此相同的结果:
#!/bin/bash
find_args="-type f '*.c' -print0"
while IFS= read -r -d '' file; do
files+=$file
done < <(find $find_args)
echo "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
如何将第二个场景修复为与第一个相同?
我的理解是,因为双引号中有单引号,单引号会被转义,这会产生一个糟糕的扩展,看起来像这样:
find -type f -name ''\''*.c'\'' -print0
Run Code Online (Sandbox Code Playgroud) 我有下面的shell脚本
var="this is a test"
ls -ltr| while read file
do
echo $var
done
echo $var
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
this is a test
this is a test
this is a test
Run Code Online (Sandbox Code Playgroud)
我如何在 while 循环中将变量“var”的值设置为“这是一个测试”,因为管道将产生一个新的子外壳,而且我也没有在主外壳中导出我的“var”变量?
据我所知,为了让孩子从父 shell 继承变量值,我们需要导出变量,但在这种情况下,变量值在没有“导出”语句的情况下被继承。
我使用 Ubuntu 16.04 并且我有一个本地化文件,一个执行许多文件的文件,这是我将自己的 GitHub 项目下载到我的机器后得到的。
该文件包含一个 Bash 脚本,名为localize.sh. 我通过~/${repo}/localize.sh.
该文件包含许多行,所有行都具有相同的基本模式(见下文),以在子会话中执行所有相关文件。
这是该文件的实际内容:
#!/bin/bash
~/${repo}/apt/security.sh
~/${repo}/apt/lemp.sh
~/${repo}/apt/certbot.sh
~/${repo}/apt/misc.sh
~/${repo}/third-party/pma.sh
~/${repo}/third-party/wp-cli.sh
~/${repo}/conf/nginx.sh
~/${repo}/conf/php.sh
~/${repo}/conf/crontab.sh
~/${repo}/local/tdm.sh
Run Code Online (Sandbox Code Playgroud)
人们可以注意到重复的~/${repo}/模式。
这不是一个大问题,但减少这些冗余字符仍然会很好,因为这个文件应该变得更大。
实现 DRY 的最简单方法是什么(不要重复该代码的自己版本?
在这种情况下,我个人不想使用一条长线。
编辑:原则上,列出的目录中没有也不应该有任何其他文件,除了localize.sh.
此外,可能 namelocalize.sh以及调用文件的操作localization是一种不好的方法;如果你认为它不好,请在旁注中批评我。
在 shell 或子 shell 中执行代码之间的这种差异是预期的吗?
$ a() { echo ${@: -1} ; }
$ echo "echo ${*: -1}" > b
$ chmod +x b
$ a 1 2 3
3
$ ./b 1 2 3
bash
$
Run Code Online (Sandbox Code Playgroud)
Debian Sid
Bash 版本 5.2.15
根据https://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping
将命令列表放在大括号之间会导致列表在当前 shell 上下文中执行。
但是当我尝试这个时:if [[ { type -t echo; } = "builtin" ]]; then echo 1; else echo 0; fi我收到以下错误:
-bash:预期条件二元运算符
-bash: `type' 附近的语法错误
没关系,我知道它不应该那样使用。现在我知道,如果我使用,if [[ $( type -t echo ) = "builtin" ]]; then echo 1; else echo 0; fi理论上我将实现所需的功能。
我发现有关防止不必要地使用子 shell 的其他问题得到了回答,但没有人解释比较没有子 shell 的命令的输出。我真正想要的是避免在不需要的地方使用子shell,如果可能的话,我真的很喜欢它在当前的shell上下文中运行这个检查——真的感觉这就是它应该如何完成的。PS 如果没有其他方法,我不介意使用变量和操作。