제가 직면하고 있는 문제에 대해 간략하게 설명하겠습니다. 제가 작성하려는 실제 애플리케이션에는 많은 부분이 있기 때문에, 작은 예제를 통해 막히는 부분을 분리해 보았습니다. 내 경우에는 디렉터리 등에서 구문 분석된 학생 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