从构造的带有空格的字符串列表中选择?

从构造的带有空格的字符串列表中选择?

我尝试创建一个包含空格的字符串列表,我想在其中进行选择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"

(我已经禁用了转义破坏路径,您由于某种原因而使用了该路径。)

相关内容