我的 bash 脚本中有一些变量可能包含文件名或未设置。它们的内容应作为附加参数传递给程序。但是当变量未设置时,这会留下一个空参数。
$ afile=/dev/null
$ anotherfile=/dev/null
$ unset empty
$ cat "$afile" "$empty" "$anotherfile"
cat: : No such file or directory
Run Code Online (Sandbox Code Playgroud)
如果没有引号,它就可以正常工作,因为附加参数被简单地省略了。但由于变量可能包含空格,因此必须在此处用引号引起来。
我知道我可以简单地将整条线包装在对空性的测试中。
if [ -z "$empty" ]; then
cat "$afile" "$anotherfile"
else
cat "$afile" "$empty" "$anotherfile"
fi
Run Code Online (Sandbox Code Playgroud)
但对每个变量进行一次测试会产生一棵巨大而复杂的决策树。
有没有更紧凑的解决方案?bash 可以省略带引号的空变量吗?
在这一行:
GCCVER:=$(shell a=`mktemp` && echo $'#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$a" -xc -; "$a"; rm "$a")
Run Code Online (Sandbox Code Playgroud)
我明白了:
*** unterminated call to function `shell': missing `)'. Stop.
Run Code Online (Sandbox Code Playgroud)
我愚蠢的迂回变量出了什么问题?
$ make --version
GNU Make 3.81
$ bash --version
GNU bash, version 4.2.8(1)-release (x86_64-pc-linux-gnu)
$ uname -a
Linux 2.6.38-10-generic #46-Ubuntu SMP x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
Run Code Online (Sandbox Code Playgroud) 我面临的问题是如何传递带参数的命令docker run
.问题是docker run
不将命令加参数作为单个字符串.它们需要作为单独的一等参数提供docker run
,例如:
#!/bin/bash
docker run --rm -it myImage bash -c "(cd build && make)"
Run Code Online (Sandbox Code Playgroud)
但是请将命令和参数视为变量的值:
#!/bin/bash -x
DOCKER_COMMAND='bash -c "(cd build && make)"'
docker run --rm -it myImage "$DOCKER_COMMAND"
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不起作用,因为docker run
不理解替换:
+ docker run --rm -it myImage 'bash -c "(cd build && make)"'
docker: Error response from daemon: oci runtime error: exec: "bash -c \"(cd build && make)\"": stat bash -c "(cd build && make)": no such file or directory. …
Run Code Online (Sandbox Code Playgroud) 我正在阅读Bash 教程,特别是单词分裂的主题.
这个名为"args"的脚本有助于演示单词拆分示例:
#!/usr/bin/env bash
printf "%d args:" $#
printf " <%s>" "$@"
echo
Run Code Online (Sandbox Code Playgroud)
一个例子:
$ ./args hello world, here is "a string of text!"
5 args: <hello> <world,> <here> <is> <a string of text!>
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.我理解这是如何工作的.
但是,当我用非空白字符替换IFS时,:
如果我直接将字符串作为参数传递,则脚本不会执行分词.
$ ./args one:two:three
1 args: <one:two:three>
Run Code Online (Sandbox Code Playgroud)
但是,如果I(1)将字符串分配给变量,然后(2)通过参数扩展将字符串传递给脚本,则脚本会对同一字符串执行分词.
$ IFS=:
$ variable="one:two:three"
$ ./args $variable
3 args: <one> <two> <three>
Run Code Online (Sandbox Code Playgroud)
为什么?具体来说,当IFS未设置且分隔符是空白字符时,为什么传递字符串作为参数会进行单词拆分,但是当IFS设置为非空白字符时却不会?
当我使用read
而不是这个脚本时,相同的字符串也会按预期进行单词拆分.
$ IFS=:
$ read a b c
one:two:three
$ echo $a $b $c
one two …
Run Code Online (Sandbox Code Playgroud) 无论你想要什么,我都试图找出一种方法来获取现有字符串的内容并将它们评估为双引号字符串.例如,如果我创建以下字符串:
$string = 'The $animal says "meow"'
$animal = 'cat'
Run Code Online (Sandbox Code Playgroud)
然后,Write-Host $string
会产生The $animal says "meow"
.如何重新评估$ string,输出(或分配给新变量)The cat says "meow"
?
多么恼人......对评论的限制使得用反引号包含代码非常困难(如果可能的话).这是我在回复下面的zdan时发表的最后两条评论的无瑕疵版本:
实际上,在考虑之后,我意识到The $animal says "meow"
在没有转义双引号的情况下期望插值是不合理的,因为如果它是一个双引号字符串开始,如果双引号没有被转义,评估将会中断.所以我想答案是这是一个两步的过程:
$newstring = $string -replace '"', '`"'
iex "`"$string`""
Run Code Online (Sandbox Code Playgroud)
后人的最后一个评论:我尝试了将所有这些全部放在一条线上的方法,并且一旦你将它们提供给iex,几乎所有你想到的东西都会破坏,但是这个有效:
iex ('"' + ($string -replace '"', '`"') + '"')
Run Code Online (Sandbox Code Playgroud) 有没有办法可靠地使用存储在变量中的任意globbing模式?如果模式包含空格和元字符,我会遇到困难.这就是我的意思.如果我有一个存储在没有空格的变量中的模式,那么事情似乎工作正常:
<prompt> touch aa.{1,2,3} "a b".{1,2,3}
<prompt> p="aa.?"
<prompt> for f in ${p} ; do echo "|$f|" ; done
|aa.1|
|aa.2|
|aa.3|
<prompt> declare -a A=($p) ; for f in "${A[@]}" ; do echo "|$f|" ; done
|aa.1|
|aa.2|
|aa.3|
Run Code Online (Sandbox Code Playgroud)
但是,只要我在模式中抛出一个空格,事情就变得站不住脚了:
<prompt> p="a b.?"
<prompt> for f in ${p} ; do echo "|$f|" ; done
|a|
|b.?|
<prompt> declare -a A=($p) ; for f in "${A[@]}" ; do echo "|$f|" ; done
|a|
|b.?|
<prompt> for f in "${p}" ; …
Run Code Online (Sandbox Code Playgroud) 我正在尝试将 json 文件拆分为各种 json 文件。输入 (r1.json) 看起来像:
{
"results" : [
{
content 1
}
,
{
content 2
}
,
{
content n
}
]
}
Run Code Online (Sandbox Code Playgroud)
我希望输出为 n 个文件:1.json、2.json、n.json。分别包含{content 1}、{content 2}和{content n}。
我试过 :
for i in {0..24}; do cat r1.json | jq '.results[$i]' >> $i.json; done
Run Code Online (Sandbox Code Playgroud)
但我有以下错误:错误:我没有定义
PWD
当当前路径包含空格时,我遇到了一个最烦人的问题,该问题发生在变量上。我的代码看起来有点像这样:
mycommand |sed -E '
s|mystuff|replacement| ;
s|'$(pwd)'|replacement| ;
'
Run Code Online (Sandbox Code Playgroud)
这很好用,除非当前路径包含空格字符。如果是,$(pwd)
则扩展为
'我的路径/有空间'而不仅仅是
mypath/有空间
这会导致 sed 表达式混乱(因为额外的引号):
sed: 1: "s|mypath/with": 未终止的替代模式
我注意到,它不利于扩大PWD这样的:${PWD//\'/}
。
关于如何解决这个问题的任何想法?
我是macosx上的shell编程的新手,并且有一点问题.我编写了以下shell脚本:
#!/bin/sh
function createlink {
source_file=$1
target_file="~/$source_file"
if [[ -f $target_file ]]; then
rm $target_file
fi
ln $source_file $target_file
}
createlink ".netrc"
Run Code Online (Sandbox Code Playgroud)
当我执行这个脚本时,我收到消息ln:〜/ .netrc:没有这样的文件或目录,我不知道为什么会这样!你看到错误吗?谢谢!
来自FOR /?
:
In addition, substitution of FOR variable references has been enhanced.
You can now use the following optional syntax:
%~I - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path …
Run Code Online (Sandbox Code Playgroud)