简介:我有一个bash脚本在后台运行一个进程,它应该作为一个普通的命令工作,并在一个命令替换块中,如$(...).脚本本身会生成一个分支到后台的进程.它可以简化为这个测试用例:
#!/bin/sh
echo something
sleep 5 &
Run Code Online (Sandbox Code Playgroud)
在shell中运行此脚本将立即返回(并打印"某些内容"),在其中运行$(...)将挂起5秒钟,等待后台"睡眠"完成.
适用于在命令替换shell中启动的任何内容,并在后台生成进程,包括该进程树中的任何子进程.似乎影响bash和zsh,没有尝试过其他人.
原始问题:我有一个bash脚本,应该将值打印到stdout,并在每次运行时将其复制到X剪贴板.
#!/bin/sh
echo something
echo something | xclip -selection clipboard
Run Code Online (Sandbox Code Playgroud)
这个脚本(让我们称之为"某事")意味着用来获取这个词(实际上是另一个命令的输出)并以不同的方式使用,例如:
$ something
something
$ xclip -o -selection clipboard
something
$ echo $(something)
^C
Run Code Online (Sandbox Code Playgroud)
打印到正常的stdout,将输出复制到剪贴板以在普通的X应用程序中使用,并且还应该能够使用带有bash命令替换的stdout,在任何命令的中间插入这个单词.
然而,bash命令替换似乎强制xclip在前台保持活跃.xclip通常守护自己,因为X剪贴板要求客户端提供剪贴板内容,默认行为是在替换剪贴板内容后退出.
在用xclip解决了这个问题之后,我做了一个我在这个问题开头写的最小测试用例,所以它似乎应用了$(...)shell 中守护进程的任何东西
谁能解释这种行为?有什么办法可以避免吗?
我很长时间以来都在试图逃避 bash 中的反引号。我尝试使用 \ 进行转义,但它不起作用。
bash 中是否可以逃避反引号?
I="hello.pdf"
var1=`cat <<EOL

\`\`\`sql
some code here
\`\`\`
EOL`
echo "$var1"
Run Code Online (Sandbox Code Playgroud)

```sql
some code here
```
Run Code Online (Sandbox Code Playgroud) 我尝试了无数的方法来得到我想要的东西,但似乎没有任何效果。我总是得到类似的东西2:not found。
我想捕获命令的输出,然后测试它是否等于“!”,如下所示:
function test() {
local testv=$(command) 2>/dev/null
if [ $(#testv) == "!" ]; then
echo "Exclamation mark!"
else
echo "No exclamation mark."
fi
}
Run Code Online (Sandbox Code Playgroud)
我应该如何重写上面的代码以避免错误test:2: = not found?
我在GNU bash,版本4.3.11.
假设我想在文件上打印唯一的行.我正在使用这种方法,它适用于文件:
$ cat a
9
10
9
11
$ awk '!seen[$0]++' a
9
10
11
Run Code Online (Sandbox Code Playgroud)
但是,如果我从stdin获取输入,在多行中使用双引号并输入到awk,则会失败:
$ echo "9
> 10
> 9
> 11" | awk '!seen[$0]++'
bash: !seen[$0]++': event not found
Run Code Online (Sandbox Code Playgroud)
也就是说,bash尝试扩展命令seen,这当然不知道,因为它是一个变量名.但它不应该发生,因为命令放在单引号内.
echo单引号,多行输入效果很好:
$ echo '9
> 10
> 9
> 11' | awk '!seen[$0]++'
9
10
11
Run Code Online (Sandbox Code Playgroud)
有趣的是,它也适用于双引号的单行输入:
$ printf "9\n10\n9\n11" | awk '!seen[$0]++'
9
10
11
Run Code Online (Sandbox Code Playgroud)
我想知道为什么Bash试图扩展历史,如果它发生在多线输入后,即使命令本身使用单引号.
其他考虑:
中间有一个管道也无法修复它:
$ echo "9
> 10
> 9
> 11" | cat - …Run Code Online (Sandbox Code Playgroud) 是否可以按照以下方式做一些事情:
echo ${$(ls)/foo/bar}
Run Code Online (Sandbox Code Playgroud)
我很确定我在某个地方看到了类似的示例,但这会导致“替换错误”错误。
我知道还有其他方法可以做到这一点,但如此短的oneliner会很有用。我错过了什么吗?
我经常在长命令中使用反引号,并用反斜杠换行符分隔以提高可读性。当我用语法替换反引号时$( ... ),出现错误。
例如,我使用curl和jq内部反引号设置了一个变量(从我的 Trello 每日待办事项列表中读取并返回除特定卡片之外的所有内容的 card.id 和 card.name):
AllCardsInDTL=\
`\
curl -s "https://api.trello.com/1/lists/$DailyTasksListID/cards\
?$WhoMe\
&fields=name,id,pos\
"\
| jq '\
.[] | \
if .name | test ("Tasks here are copied.*") \
then empty \
else .id, .name \
end \
'\
` # End of AllCardsInDTL=
Run Code Online (Sandbox Code Playgroud)
这没有问题,shell 变量由 ID 和 Name 值的交替行组成。
但是,如果我用 替换反引号$( ... ),则会收到错误jq:
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at …Run Code Online (Sandbox Code Playgroud) 我试图逃避AWK的反斜杠.这是我想要做的一个例子.
说,我有一个变量
$echo $a
hi
Run Code Online (Sandbox Code Playgroud)
以下作品
$echo $a | awk '{printf("\\\"%s\"",$1)'}
\"hi"
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试使用命令替换将相同命令的输出保存到变量时,我收到以下错误:
$ q=`echo $a | awk '{printf("\\\"%s\"",$1)'}`
awk: {printf("\\"%s\"",$1)}
awk: ^ backslash not last character on line
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么命令替换打破了AWK.非常感谢你的帮助.
我正在尝试编写短脚本,以及以下命令:
echo "aaa111 bbb111" | xargs -I {} echo {} | sed 's/111/222/g'
Run Code Online (Sandbox Code Playgroud)
回归aaa222 bbb222,这是我所期待的.
我期待下一个命令:
echo "aaa111 bbb111" | xargs -I {} echo $(echo {} | sed 's/111/222/g')
Run Code Online (Sandbox Code Playgroud)
返回相同,但它返回aaa111 bbb111!这是为什么?
UPD:我想要实现的目标:
我有很多文件,比如pic30-coff-gcc,pic30-coff-ag等等,我需要为每个文件创建一个符号链接,比如pic30-gcc- > pic30-coff-gcc等.
所以我写了这个:
ls|grep 'coff-'|xargs -I {} ln -s {} $(echo {} | sed 's/coff-//g')
Run Code Online (Sandbox Code Playgroud)
它不起作用:对于每个文件,它报告该文件存在.我检查了这样的命令:
ls|grep 'coff-'|xargs -I {} echo "ln -s {} $(echo {} | sed 's/coff-//g')"
Run Code Online (Sandbox Code Playgroud)
是的,这sed部分不起作用:
ln -s pic30-coff-gcc …Run Code Online (Sandbox Code Playgroud) 更准确地说,为什么
"`command "$variable"`"
Run Code Online (Sandbox Code Playgroud)
将外部引号视为包含内部引号,而不是将变量扩展到任何引号之外?
我用来测试的确切命令类似于另一个 stackoverflow 问题中关于使用命令替换时正确引用方法的示例:
fileName="some path with/spaces"
echo "`dirname "$fileName"`"
Run Code Online (Sandbox Code Playgroud)
它正确地回应了“some path with”,而不是因为参数数量无效而抱怨。
我阅读了 Bash 的手册页,它在“扩展”一章的“命令替换”部分中指出,新样式的 $() 替换保留了括号之间任何字符的含义,但是,关于反引号,它只提到反斜杠起作用以有限的方式:
当使用旧式反引号替换形式时,反斜杠保留其字面意义,除非后跟
$,`, 或\。前面没有反斜杠的第一个反引号终止命令替换。
我的第一个想法是反引号做同样的事情,除了提到的例外,因此“引用”内部双引号,但是,我被告知事实并非如此。将我指向这个方向的第二个观察是
a=\$b
b=hello
echo `echo $a`
Run Code Online (Sandbox Code Playgroud)
打印“$b”。如果反引号让美元符号被解释,那么第一个变量替换应该在调用子shell之前发生,子shell扩展字符串“$b”,产生“hello”。根据手册页的上述摘录,我什至可以确保美元符号确实被引用,通过使用
echo `echo \$a`
Run Code Online (Sandbox Code Playgroud)
结果还是一样。
不过,第三个观察结果让我有些怀疑:
echo `echo \\a`
Run Code Online (Sandbox Code Playgroud)
结果:“\a”
echo \a
Run Code Online (Sandbox Code Playgroud)
结果:一个
在这里,似乎两个反斜杠都被保留了,直到子外壳发挥作用,即使手册页指出反引号中的反斜杠在后面跟另一个反斜杠时没有其字面意义。编辑:^ 在这方面,一切都按预期工作,我一定使用了错误的 shell(在我的另一个终端中使用了 tcsh,并且字符与“a”不同)。
虽然我无法找出实际发生的情况,但在我寻找答案时,我遇到了一些人提到了有关命令替换的术语“引用上下文”,但没有对其含义或位置进行任何解释它被描述。我在 Bash 参考资料(gnu.org、tldp、man bash)或通过 DuckDuckGo 中都没有找到任何对“引用上下文”的真正参考。
除了了解正在发生的事情之外,我更希望获得一些关于如何从中辨别这种行为的参考或指导,因为我认为我可能没有将一些自然产生的部分放在一起。否则我会忘记答案。
对于那些建议人们使用新式美元符号和括号替换的人:在大约。具有数十或数百种不同专有环境的 50 年老 Unix 机器(不能为更新的环境扔掉外壳),当必须编写在任何人可能使用的大多数外壳之间兼容的脚本时,这不是一种选择。
感谢任何可以帮助我的人。
我有一个简单的shell脚本,其中包含以下内容:
#!/usr/bin/env bash
set -eu
set -o pipefail
Run Code Online (Sandbox Code Playgroud)
我还具有以下功能:
foo() {
printf "Foo working... "
echo "Failed!"
false # point of interest #1
true # point of interest #2
}
Run Code Online (Sandbox Code Playgroud)
执行foo()作为常规命令按预期工作:脚本退出时#1,由于返回码false是非零和我们使用set -e。
我的目标是将函数的输出捕获到foo()变量中,并仅在执行时出现错误时打印它foo()。这是我想出的:
printf "Doing something that could fail... "
if a="$(foo 2>&1)"; then
echo "Success!"
else
code=$?
echo "Error:"
printf "${a}"
exit $code
fi
Run Code Online (Sandbox Code Playgroud)
该脚本不会在处退出,#1并且会执行"Success!"该if语句的路径。注释掉trueat将#2导致执行语句的"Error:"路径 …