![从构造的带有空格的字符串列表中选择?](https://linux22.com/image/215336/%E4%BB%8E%E6%9E%84%E9%80%A0%E7%9A%84%E5%B8%A6%E6%9C%89%E7%A9%BA%E6%A0%BC%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%88%97%E8%A1%A8%E4%B8%AD%E9%80%89%E6%8B%A9%EF%BC%9F.png)
我尝试创建一个包含空格的字符串列表,我想在其中进行选择select
- 如下所示:
sel=""
while read l
do
sel=$(printf "%s '%s'" "$sel" "$l")
done< <(cd /some/data/directory;du -sh *)
select x in $sel
do
break
done
该字符串sel
看起来像预期的:"597G 2022" "49G analysis" "25K @Recycle"
,但选择看起来像:
1) "597G 3) "49G 5) "25K
2) 2022" 4) analysis" 6) @Recycle"
#?
我想要实现的目标当然是:
1) 597G 2022
2) 49G analysis
3) 25K @Recycle
#?
更一般地说,您可以在以某种方式从多个数据源构建的字符串之间进行选择。我在几个地方寻找灵感,比如这里,但它不太适合我的情况。
编辑
我忘了提,这个 bash 相当旧了(遗憾的是我无法更新它):
[admin@CoMind-UniCron ~]# bash --version
GNU bash, version 3.2.57(1)-release (x86_64-QNAP-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
答案1
您想要在那里使用多个字符串的数组,而不是必须由 shell 正确分割的单个字符串。像这样的东西:
#!/bin/bash
while read l
do
sel+=( "$l" )
done< <(cd /some/data/directory;du -sh *)
select x in "${sel[@]}"
do
break
done
这会产生预期的输出:
$ foo.sh
1) 597G 2022
2) 50G analysis
3) 32K @Recycle
#?
一种更安全的方法,可以处理除换行符之外的任意文件/目录名称,并且只是稍微复杂一点,但可以在所有情况下使用而无需担心:
#!/bin/bash
while IFS= read -r l
do
sel+=( "$l" )
done< <(shopt -s nullglob dotglob; cd /some/data/directory && du -sh -- *)
select x in "${sel[@]}"
do
break
done
答案2
这实在是想多了。
#!/usr/bin/env bash
IFS='
'
select x in $(cd /some/data/directory && du -sh -- *); do
break
done
unset IFS # or save/restore it explicitly
作为额外的好处,这里唯一的攻击是select
.
打字稿:
$ ./cg
1) 0 0
2) 0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
3) 0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
4) 0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a
5) 0 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ą
6) 60k 1028501896.pdf
7) 0 a
8) 16k a.bkp
9) 36k a.cpio
10) 10k a.d
11) 36k a.patch
12) 60k a.pax
13) 84k a.png
14) 4k b.cpio
15) 32k b.pax
16) 12k b.tar
17) 0 bugreport.cgi?bug=910770;mbox=yes;mboxmaint=yes
18) 74.2M build-output
19) 796k busybox
20) 428k busybox_1%3a1.30.1-6+b3_amd64.deb
21) 0 CB_Unix
22) 4k cg
#?
像您所做的那样的引用不起作用,因为引用删除仅适用于原始单词;参数扩展的结果只是字段分割(和通配符)。为此,您需要将字符串标记为输入:
eval "select x in $sel
do
break
done"
出于明显的原因,您确实不应该这样做,因为您实际上尚未转义文件名:
$ ./cg
./cg: eval: line 11: unexpected EOF while looking for matching `''
./cg: eval: line 15: syntax error: unexpected end of file
如果你真的需要为每一行分叉一个进程并且真的需要将 du 输出存储在一个大字符串中那么你应该这样做
#!/usr/bin/env bash
sel=
while read -r l; do
sel="$(printf '%s %q' "$sel" "$l")"
done < <(cd /some/data/directory && du -sh -- *)
eval "select x in $sel; do
break
done"
(我已经禁用了转义破坏路径,您由于某种原因而使用了该路径。)