我已经习惯了 while 循环中bash的内置read函数,例如:
echo "0 1
1 1
1 2
2 3" |\
while read A B; do
echo $A + $B | bc;
done
Run Code Online (Sandbox Code Playgroud)
我一直在做一些make项目,拆分文件和存储中间结果变得谨慎。因此,我经常最终将单行分解为变量。虽然下面的例子效果很好,
head -n1 somefile | while read A B C D E FOO; do [... use vars here ...]; done
Run Code Online (Sandbox Code Playgroud)
这有点愚蠢,因为 while 循环永远不会运行超过一次。但没有while,
head -n1 somefile | read A B C D E FOO; [... use vars here ...]
Run Code Online (Sandbox Code Playgroud)
当我使用它们时,读取变量总是空的。我从未注意到 的这种行为read,因为通常我会使用 while 循环来处理许多类似的行。如何在没有 while 循环的情况下使用 …
我rbenv在机器上安装了(ruby 版本管理器),它的工作原理是这样的:
$ rbenv local
2.3.1
Run Code Online (Sandbox Code Playgroud)
写入标准输出我的 ruby 的本地版本。我想拯救这个版本并在一个变量中声明它以在另一个场合重用。
$ declare -r RUBY_DEFINED_VERSION=$(rbenv local)
$ echo Using ruby version $RUBY_DEFINED_VERSION
Using ruby version 2.3.1
Run Code Online (Sandbox Code Playgroud)
有用!
但我不想使用子外壳来完成工作(使用$()或``)。我想使用相同的外壳,我不想创建一个tmp文件来完成这项工作。
有没有办法做到这一点?
注意: declare -r不是强制性的,它可以是一个简单的var=FOOBAR.
我想将mktempas 参数的结果传递给命令,比方说gcc -o。gcc -o $(mktemp)导致使用结果,但我需要弄清楚结果。
我唯一能想到的是gcc -o $(out=$(mktemp); echo $out),但这不会将值打印到控制台,而是用作参数值,这是正确的 afaik。
有什么办法可以得到mktemp打印到控制台的结果。
我有能力在脚本中解决这个问题。我想通过您希望提出的单行解决方案来拓宽我的知识。
我想bash在 Ubuntu 19.04 上使用它。
我对在子 shell 中运行命令的理解是,当前 shell 被分叉,然后子 shell 进一步执行fork所需exec的命令。
在 bash 和 zsh 中运行以下命令时,我看到奇怪的行为:
$ ( sleep 5 && sleep 6 )
在bash中运行时:
$ echo $$
6410
$ ( sleep 5 && sleep 6 )
Run Code Online (Sandbox Code Playgroud)
ps给出以下内容:
CMD:睡眠 5
PID:6590
PPID:6589
然后:
CMD:睡眠 6
PID:6616
PPID:6589
这对我来说都是有道理的。sleep 5并且sleep 6两者具有相同的父级(大概是子shell)。
但是,在zsh中,我得到以下信息:
$ echo $$
1987
$ ( sleep 5 && sleep 6 )
Run Code Online (Sandbox Code Playgroud)
ps给出以下内容:
CMD:睡眠 5
PID: …
脚本通常以 shebang 开头,例如#!/usr/bin/env bash,它指定要用于执行的 shell。shebang 不存在时的执行行为似乎取决于调用 shell。无论哪种方式,脚本都是从“新”shell 运行的,该 shell 不知道调用 shell 中定义的变量和函数。
或者,也可以将脚本source放入 shell 中,根据我的理解,这相当于将脚本内容复制粘贴到当前 shell 中。如果脚本中定义了任何函数或变量,那么它们在“执行”后将保留在调用 shell 中,这可能是不可取的。
这两个选项之间有什么关系吗?是否可以将脚本作为调用 shell 的子 shell 来执行,这样我们就可以访问调用 shell 中定义的所有内容,但不会修改它(除非可能使用export这样的命令)?
写作(source myscript.sh)似乎就是我所追求的;这是正确的做法吗?是否有一个等效的 shebang 可以通过调用来产生相同的行为./myscript.sh?
在 bash 中,你有这个方便的变量: $BASHPID ,它总是返回当前运行的子 shell 的 PID。如何在 ksh 中获取子 shell 的 PID?例如看下面的代码:
#!/usr/bin/ksh93
echo "PID at start: $$"
function run_in_background {
echo "PID in run_in_background $$"
run_something &
echo "PID of backgrounded run_something: $!"
}
function run_something {
echo "*** PID in run_something: $$"
sleep 10;
}
run_in_background
echo "PID of run in background $!"
Run Code Online (Sandbox Code Playgroud)
这将输出以下内容:
PID at start: 5328
PID in run_in_background 5328
*** PID in run_something: 5328
PID of backgrounded run_something: 5329
PID of run in background …Run Code Online (Sandbox Code Playgroud) 许多简单的命令 usingxargs可以重写为使用子外壳的命令。例如,这是我今天早些时候使用的东西,用于连接 中的 10 个最大的二进制文件/usr/bin,使用 subshell 与 xargs 编写:
子外壳:
$ cat $(du -sh /usr/bin/* | sort -h | tail | cut -d " " -f 2 | tr "\n" " ")
Run Code Online (Sandbox Code Playgroud)
xargs:
$ du -sh /usr/bin/* | sort -h | tail | cut -d " " -f 2 | tr "\n" " " | xargs cat
Run Code Online (Sandbox Code Playgroud)
那么什么时候应该使用子shell,什么时候应该使用xargs?
cut 的分隔符是一个硬制表符,显然在 SE 上无法正确显示。
希望这个问题不是太笼统。我对 shell 脚本很陌生,我来自计算机体系结构/非脚本编程背景。我在我工作的脚本中注意到,很少通过围绕整个脚本创建子 shell 来编写脚本。在我正在编写的脚本中,当我可以用一个子 shell 包围它时,我就是这样,因为它可以防止它与调用我的其他脚本混淆(以防万一)。由于与此方法相关的一些开销,这不是一种常见做法吗?我很难在网上找到这个。
例子:
#!/bin/bash
( #Start of subshell
echo "Some stuff here"
) #End of subshell
Run Code Online (Sandbox Code Playgroud) 我最近一直在尝试为一个小项目创建一个 shell 脚本,但由于某种原因,该flock命令对我不起作用。每当我在子 shell 中以原子方式调用它并将其置于后台时,其他程序似乎能够读取/写入锁定的文件。
Bash 会话:
guest@guest ~ $ touch ./temp
guest@guest ~ $ ( flock -x 3 && sleep 99999999999; ) 3>./temp &
[1] 22874
guest@guest ~ $ cat ./temp
guest@guest ~ $ echo this is a test >./temp
guest@guest ~ $ cat ./temp
this is a test
guest@guest ~ $ jobs
[1]+ Running ( flock -x 3 && sleep 99999999999 ) 3>./temp &
guest@guest ~ $ bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Copyright (C) …Run Code Online (Sandbox Code Playgroud) 跑步
bash -c 'bash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;'
Run Code Online (Sandbox Code Playgroud)
结果test1被打印到控制台并echo $?打印1在我的理解中是正确的,因为命令应该返回内部[b/d]ash -c返回的内容,而
dash -c 'dash -c "echo test1; exit 1;" &> /tmp/x; buildresult=$?; tail -n 100 /tmp/x; exit $buildresult;'
Run Code Online (Sandbox Code Playgroud)
导致相同的输出,但0根据返回echo $?。
我想了解这种差异,以拓宽我对 shell 和可移植 shell 编程的理解。
我在 Ubuntu 17.10 (Artful Aardvark) 上使用bash4.4.12 和dash0.5.8-2.3ubuntu1。
subshell ×10
bash ×5
shell ×4
shell-script ×3
command-line ×2
conventions ×1
dash ×1
exit-status ×1
fedora ×1
flock ×1
ksh ×1
linux ×1
performance ×1
pipe ×1
read ×1
scripting ×1
variable ×1
xargs ×1
zsh ×1