bash中引用参数的行列表

bash中引用参数的行列表,bash,Bash,我有一个命令,返回由引号包围的网络接口列表:- networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" | sed 's#([^:]*:\ \([^,]*\),.*#\"\1\"#' 现在我需要将其转换为另一个命令的参数:- networksetup -ordernetworkservices "Wi-Fi" <the other interfaces>. 但这是失败的。我的引文

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

networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" | sed 's#([^:]*:\ \([^,]*\),.*#\"\1\"#'
现在我需要将其转换为另一个命令的参数:-

networksetup -ordernetworkservices "Wi-Fi" <the other interfaces>.
但这是失败的。我的引文似乎被删掉了,但我不明白为什么

echo $services 
给我

"Dell Universal Dock D6000" "USB 10/100/1000 LAN" "Bluetooth PAN" "Thunderbolt Bridge"
我还尝试了上面的方法,用单引号和双引号括起变量

命令将向shell发出:

"Dell Universal Dock D6000"
"USB 10/100/1000 LAN"
"Bluetooth PAN"
"Thunderbolt Bridge"
我最终需要的是:

networksetup -ordernetworkservices Wi-Fi "Dell Universal Dock D600" "USB 10/100/1000 LAN" "Bluetooth PAN" "Thunderbolt Bridge"

我知道答案就在眼前,但我想不起来了。

没有这样的网络设置程序,很难说出来。但是你看:

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"
以及:


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

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"
以及:


第一:在shell中,您应该将引号视为围绕数据的东西,而不是数据中的东西。你在数据中嵌入引号,并期望它们像围绕着数据一样工作,但事实并非如此。更具体地说,shell在替换变量值之前会解析引号、转义符和一系列其他内容,因此,如果变量的值中有引号,那么当它被替换到命令行中时,它就太晚了,无法达到预期的效果

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


那么,如何将networksetup的输出放入数组中呢?好吧,如果您有BashV4,您可以使用readarray,但macOS只附带BashV3。你仍然可以做,只是多做一点工作。您有一个读取循环,从networksetup读取每行输出,处理后删除除服务名称之外的所有内容,并且不添加引号。但是你不能让循环成为管道的一部分,否则它会在子shell中运行,当它退出时数据会丢失,所以你必须首先用<命令替换重定向循环的输入:在shell中,你应该把引号看作是围绕数据的东西,而不是数据中的东西。你在数据中嵌入引号,并期望它们像围绕着数据一样工作,但事实并非如此。更具体地说,shell在替换变量值之前会解析引号、转义符和一系列其他内容,因此,如果变量的值中有引号,那么当它被替换到命令行中时,它就太晚了,无法达到预期的效果

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


那么,如何将networksetup的输出放入数组中呢?好吧,如果您有BashV4,您可以使用readarray,但macOS只附带BashV3。你仍然可以做,只是多做一点工作。您有一个读取循环,从networksetup读取每行输出,处理后删除除服务名称之外的所有内容,并且不添加引号。但是,您不能让循环成为管道的一部分,否则它将在子shell中运行,退出时数据将丢失,因此您必须使用<命令替换重定向循环的输入。您似乎希望重新排列网络端口,以便Wi-Fi领先于其他所有内容

尝试创建命令,就像在命令行中键入命令一样。尽管如此,这是一个按顺序排列论点的问题。因此,不要在网络名称周围加引号,只要让参数代表它们自己,例如

networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#'
现在你可以把它们放在一起

但这并不像预期的那样有效,因为硬件端口内部有空间,因此需要引用。要解决这个问题,可以用NUL字节而不是换行符来分隔硬件端口。要用NUL字节替换换行符,请使用


现在,xargs将参数正确地传递给networksetup。

您似乎希望重新排列网络端口,以便Wi-Fi优先于其他所有端口

尝试创建命令,就像在命令行中键入命令一样。尽管如此,这是一个按顺序排列论点的问题。因此,不要在网络名称周围加引号,只要让参数代表它们自己,例如

networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#'
现在你可以把它们放在一起

但这并不像预期的那样有效,因为硬件端口内部有空间,因此需要引用。要解决这个问题,可以用NUL字节而不是换行符来分隔硬件端口。要用NUL字节替换换行符,请使用

现在,xargs将参数正确地传递给networksetup。

Try$services?请参阅:,特别是在以下情况下:
我记得没错。您应该在数组中捕获接口名称,并将其用于命令行参数。我正在基于只有在运行时才知道的信息构造一个命令,但我无法找到一种方法将该行列表放入由双引号包围的参数列表中,因此它被接受为命令的单词列表。即使把它放在数组中,它也会被解析到没有引号的数组中。很难测试和实验,因为我最喜欢的是什么?系统没有网络设置。您能否编写一个模拟函数,并使用它来生成输出,您的命令会生成输出,并在您的问题中使用它?请尝试$services?请参阅:,如果我没有记错的话。您应该在数组中捕获接口名称,并将其用于命令行参数。我正在基于只有在运行时才知道的信息构造一个命令,但我无法找到一种方法将该行列表放入由双引号包围的参数列表中,因此它被接受为命令的单词列表。即使把它放在数组中,它也会被解析到没有引号的数组中。很难测试和实验,因为我最喜欢的是什么?系统没有网络设置。您能否编写一个模拟函数,并使用它生成输出,您的命令生成输出,并在您的问题中使用它?
$ 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)
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#'
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#' |
    xargs networksetup -ordernetworkservices Wi-Fi
networksetup -listnetworkserviceorder | grep "Hardware Port" | grep -v "Wi-Fi" |
    sed 's#([^:]*:\ \([^,]*\),.*#\1#' | tr -s '\n' '\0' |
    xargs -0 networksetup -ordernetworkservices Wi-Fi