首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在bash中引用参数的行列表

在bash中引用参数的行列表
EN

Stack Overflow用户
提问于 2018-04-09 04:55:40
回答 3查看 134关注 0票数 2

我有一个命令,它返回一个由引号包围的网络接口列表:-

代码语言:javascript
复制
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" | sed 's#([^:]*:\ \([^,]*\),.*#\"\1\"#'

现在我需要把它转化为另一个命令的论点:-

代码语言:javascript
复制
networksetup -ordernetworkservices "Wi-Fi" <the other interfaces>.

我试过了

代码语言:javascript
复制
services=`networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" | sed 's#([^:]*:\ \([^,]*\),.*#\"\1\"#' | paste -sd " " -`
# set order after above
networksetup -ordernetworkservices Wi-Fi $services

但那是失败的。看来我的引号被删掉了,但我不知道为什么。

代码语言:javascript
复制
echo $services 

给我

代码语言:javascript
复制
"Dell Universal Dock D6000" "USB 10/100/1000 LAN" "Bluetooth PAN" "Thunderbolt Bridge"

我也尝试了上面的变量,包括单引号和双引号。

该命令将向shell吐出:

代码语言:javascript
复制
"Dell Universal Dock D6000"
"USB 10/100/1000 LAN"
"Bluetooth PAN"
"Thunderbolt Bridge"

我最终需要的是:

代码语言:javascript
复制
networksetup -ordernetworkservices Wi-Fi "Dell Universal Dock D600" "USB 10/100/1000 LAN" "Bluetooth PAN" "Thunderbolt Bridge"

我知道答案就在我面前,但我错过了。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-04-09 06:42:05

首先:在shell中,您应该把引号看作是数据周围的东西,而不是数据中的东西。你在你的数据中嵌入引号,期望它们就像在数据周围一样工作,但它并不是那样工作的。更具体地说,shell在替换变量值之前会解析引号(和转义以及其他一些东西),因此如果变量的值中有引号,那么当它被替换到命令行时,它就太晚了,无法达到预期的效果。

那么,当每个端口名可能包含空格时,您将如何维护它们作为一个单独的项呢?在bash中,您可以将它们存储在一个数组中,并使用"${arrayname[@]}"扩展数组--双引号和[@]的组合使得bash将每个数组元素作为一个单独的单词来处理,本质上就像每个项目都被单独引用一样。

那么如何将networksetup的输出输入到数组中呢?如果您有bash 4,您可以使用readarray,但是macOS只附带bash v3。你还是能做到的,只是再多做一点工作。您有一个read循环读取networksetup的每一行输出,处理后可以删除除服务名称之外的所有内容(并且没有添加引号)。但是,不能让循环成为管道的一部分,否则它将在子subshell中运行,退出时数据将丢失,因此必须用< <( )重定向循环的输入。就像这样:

代码语言:javascript
复制
service_list=()
while read service; do
    service_list+=("$service")    # Note: double-quotes and parens are both needed
done < <(networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" | sed 's#([^:]*:\ \([^,]*\),.*#\1#')

networksetup -ordernetworkservices Wi-Fi "${service_list[@]}"

顺便说一句,对于@userunknown和其他无法访问macOS试图解决/测试这个问题的用户,下面是一个示例输出:

代码语言:javascript
复制
$ networksetup -listnetworkserviceorder
An asterisk (*) denotes that a network service is disabled.
(1) iPhone USB
(Hardware Port: iPhone USB, Device: en5)

(2) Ethernet
(Hardware Port: Ethernet, Device: en0)

(3) Wi-Fi
(Hardware Port: Wi-Fi, Device: en1)

(*) FireWire
(Hardware Port: FireWire, Device: fw0)

(4) Bluetooth PAN
(Hardware Port: Bluetooth PAN, Device: en4)

(5) Thunderbolt Bridge
(Hardware Port: Thunderbolt Bridge, Device: bridge0)
票数 2
EN

Stack Overflow用户

发布于 2018-04-09 06:22:35

如果没有这样的网络设置程序,就很难说了。但是你看:

代码语言:javascript
复制
mock () {
  echo '"Dell Universal Dock D6000"
"USB 10/100/1000 LAN"
"Bluetooth PAN"
"Thunderbolt Bridge"'
}

mock
"Dell Universal Dock D6000"
"USB 10/100/1000 LAN"
"Bluetooth PAN"
"Thunderbolt Bridge"

echo $(mock)
"Dell Universal Dock D6000" "USB 10/100/1000 LAN" "Bluetooth PAN" "Thunderbolt Bridge"

echo "$(mock)"
"Dell Universal Dock D6000"
"USB 10/100/1000 LAN"
"Bluetooth PAN"
"Thunderbolt Bridge"

以及:

代码语言:javascript
复制
for s in $(echo "$(mock)"); do echo "<"$s">"; done 
<"Dell>
<Universal>
<Dock>
<D6000">
<"USB>
<10/100/1000>
<LAN">
<"Bluetooth>
<PAN">
<"Thunderbolt>
<Bridge">

for s in "$(echo "$(mock)")"; do echo "<"$s">"; done 
<"Dell Universal Dock D6000" "USB 10/100/1000 LAN" "Bluetooth PAN" "Thunderbolt Bridge">
票数 2
EN

Stack Overflow用户

发布于 2018-04-09 06:57:27

您似乎希望重新排序网络端口,以便Wi-Fi在其他方面处于领先地位。

您尝试创建一个命令,就像在命令行中键入它一样。虽然,这是一个把论点按顺序排列的问题。所以,不要把引号放在网络名称的周围,只要让这些参数代表自己,就可以了。

代码语言:javascript
复制
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#'

现在你可以把它们和xargs放在一起了

代码语言:javascript
复制
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#' |
    xargs networksetup -ordernetworkservices Wi-Fi

但是这不像预期的那样工作,因为硬件端口内部有空间(因此可以感知到对引号的需求)。要解决这个问题,您可以使用NUL字节而不是换行符来分隔硬件端口。若要用NUL字节替换换行符,请使用tr

代码语言:javascript
复制
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#' | tr -s '\n' '\0' |
    xargs -0 networksetup -ordernetworkservices Wi-Fi

现在,xargs正确地将参数传递给网络设置。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49725795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档