スペースを含む構成された文字列のリストから選択しますか?

スペースを含む構成された文字列のリストから選択しますか?

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

シェルによって適切に分割される必要がある単一の文字列ではなく、複数の文字列の配列が必要です。このような:

#!/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"

(何らかの理由で使用しているルートを破るために脱出を無効にしました。)

関連情報