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

중괄호 확장은 임의의 문자열을 생성할 수 있는 메커니즘입니다.
...
올바르게 형성된 중괄호 확장에는 다음이 포함되어야 합니다.인용되지 않음여는 중괄호와 닫는 중괄호, 그리고 적어도 하나인용되지 않음쉼표 또는 유효한 시퀀스 표현입니다. 잘못 형성된 중괄호 확장은 변경되지 않습니다.

내가 이해하는 바에 따르면, 각 줄을 읽을 때 기본적으로 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

관련 정보