bash中括弧拡張(離散数字)のために行を読み取り、エコー中に使用しようとしましたが、拡張されません。

bash中括弧拡張(離散数字)のために行を読み取り、エコー中に使用しようとしましたが、拡張されません。

私が直面している問題について簡単に説明します。私が作成したい実際のアプリケーションには多くの部分があるので、小さな例で詰まっている部分を分離してみました。私の場合は、ディレクトリなどで解析された学生ID番号の仮想リストに似たファイルID番号が含まれます。


何から始めるべきですか?

試して利用しようbash 支柱の拡張、生徒ディレクトリに似たコンテンツが次のコンテンツに解析されました。

$ cat student_id_potential_expansions
0000{11,24}
0001{32,38,81}
0002{02,80,81,89,97}

望む行動

この入力を使用して、以下のように独自の(Bourne Again)シェルスクリプトを作成したいと思います。

#!/bin/bash

get_transcripts_for_id.sh -id 000011
get_transcripts_for_id.sh -id 000024
get_transcripts_for_id.sh -id 000132
get_transcripts_for_id.sh -id 000133
get_transcripts_for_id.sh -id 000181
get_transcripts_for_id.sh -id 000202
...

など。

以前は、このコマンドについてあまり心配していませんでした。

awk '{print "get_transcripts_for_id.sh -id" $0}' student_id_list > my_shell_script.sh

または

sed 's/^\(.*\)$/get_transcripts_for_id.sh -id \1/' student_id_list > my_shell_script.sh

これで、student_id_list潜在的な拡張リストからID番号のリスト(上記)を取得したいと思います。

基本的な問題はわかるようですが、どのように解決すべきかわかりません。次のように、希望のリスト部分を取得できます。

$ echo 0000{11,24} | tr ' ' '\n'
000011
000024

$ echo 0001{32,38,81} | tr ' ' '\n'
000132
000138
000181

$ echo 0002{02,80,81,89,97} | tr ' ' '\n'
000202
000280
000281
000289
000297

しかし、私が考えた最初のコマンドは拡張されませんでした。

# doesn't work, as you can see
$ while read -r line; do echo $line; done < student_id_potential_expansions
0000{11,24}
0001{32,38,81}
0002{02,80,81,89,97}

欲しくない各行をコピー/貼り付けたいです。潜在的に拡張可能な行は数百から数千個あります。これはどこから来るのかを知っている他の人が解析したものであり、レコードから元の解析を行った人にはアクセスできません。また、私の各行は次のようになります。

0000009{882,739,861,014,952,611,862,935,976,916,080,697,323,843,840,487,517,407,256,756,374,682,162,930,758,157,770,505,867,233,198,131,917,848,613,247,961,261,616,392,876,747,873,148,844,849,280,626,817,819,174,771,172,284,217,200,018,624,418,292,642,529,755,855,647,317,881,962,975,237,635,805,298,835,053}

私の理解

bash マニュアルでは、セクション3.5.1

中括弧拡張は、任意の文字列を生成できるメカニズムです。
...
正しく形成された中括弧の拡張には、次のものを含める必要があります。引用しない開中括弧と閉じ中括弧、および少なくとも1つ引用しないコンマまたは有効なシーケンス表現です。誤って形成された中括弧の拡張は変更されません。

私が理解しているように、各行を読むときにデフォルトでwhileループ内のすべての項目に供給される文字列が提供されます。つまり、上記の例では、まず次$lineのように提供します"0000{11,24}"(引用符を参照)。さらに、最初のループが次のコマンドを生成するのと同じです。

echo "0000{11,24}"

$line繰り返しますが、私のループにいなくても引用符を確認してくださいwhile。これが一貫していることを確認するために、次のコマンドを実行して次のような結果を得ました。

$ echo "0000{11,24}"
0000{11,24}

$ echo "0001{32,38,81}"
0001{32,38,81}

$ echo "0002{02,80,81,89,97}"
0002{02,80,81,89,97}

したがって、私が知っている限り、すべての中括弧({および})とカンマは引用されています。 bashのマニュアルでは、これは間違った拡張文が発生することを示しています。だから主な質問は、$line読んだすべての内容の引用を解除するか、文字列を解放するにはどうすればよいですか?


私の試み/研究

この記事が長すぎる危険性があるので、ここで私が試したいくつかを紹介します。

裏返すこれだから私の投稿では、私の問題は単語の分離の問題ではないと確信しています。

この回答そしてこのコメント、具体的に言及

では、拡張が拡張前に発生するので、2段階式を生成する他のトリックを使用したり、他のトリックを使用する以外に、これを行う方法はないと思いますbash{}$eval

努力するつもりです。

$ while read -r line; do eval "$line"; done < student_id_potential_expansions
bash: 000011: command not found
bash: 000132: command not found
bash: 000202: command not found

そして

$ while read -r line; do echo $(eval "$line"); done < student_id_potential_expansions
bash: 000011: command not found

bash: 000132: command not found

bash: 000202: command not found

シェルがコマンドを実行(評価)しようとする前に、最初の拡張のみが実行されるようです。

私も次のコマンドを試しました。コメントを参照してくださいここ

$ while read -r line; do expansions=$line; echo $expansions; done < trying_inner_echo.txt
$(echo 0000{11,24})
$(echo 0001{32,38,81})
$(echo 0002{02,80,81,89,97})

$ while read -r line; do echo $line; done < trying_inner_echo.txt
$(echo 0000{11,24})
$(echo 0001{32,38,81})
$(echo 0002{02,80,81,89,97})

$ while read -r line; do threads=${line}; exec $threads; done < trying_inner_echo.efl
bash: exec: $(echo: not found
bash: exec: $(echo: not found
bash: exec: $(echo: not found

$ while read -r line; do threads=${line}; exec "${threads}"; done < trying_inner_echo.txt
bash: exec: $(echo 0000{11,24}): not found
bash: exec: $(echo 0001{32,38,81}): not found
bash: exec: $(echo 0002{02,80,81,89,97}): not found

他の試み:

$ while read -r line; do echo "$line"; done < student_id_potential_expansions
$ while read -r line; do echo "$(echo $line)"; done < student_id_potential_expansions

システムメッセージ

$ uname -a
CYGWIN_NT-10.0 C-D-ENG-E-INT3 2.11.2(0.329/5/3) 2018-11-08 14:34 x86_64 Cygwin

$ bash --version
GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ systeminfo | sed -n 's/^OS\ *//p'
Name:                   Microsoft Windows 10 Enterprise
Version:                10.0.17134 N/A Build 17134
Manufacturer:           Microsoft Corporation
Configuration:          Member Workstation
Build Type:             Multiprocessor Free

私が使ったもの(@EchoMike444のおかげで)

@EchoMike444の答えは絶対に正確で、私がどこにいるべきかを案内してくれました。回答に表示されているものとは若干異なるものを使用しているので、回答コメントの代わりにここに入力します。コメントから:

私をそこに連れて行ってくれてありがとう。私が使うとき

while read -r line; do 
  eval "echo $line"  ## RIGHT!
done < student_id_potential_expansions | tr ' ' '\n' 

私が探している結果を得ました。そこに行くのに助けが必要ですecho $(eval "$line") # wrong!

答え1

秘訣は次のとおりです。eval

非常に最小限の例:

( echo '000{90,91}' ; echo '002{10,11}' ; echo '110{50,51}' ) | \
       while read L ; do eval "echo $L" | tr ' ' '\n'  ; done

関連情報