너무 순진한 질문일지도 모르지만 이해가 안되서 여쭤보고 싶었는데... 문제에 대한 해결책을 찾다가 발견했어요이 매우 흥미로운 게시물[while|for]
Bash에서 루프를 사용하는 것이 나쁜 습관으로 간주되는 이유 게시물에 좋은 설명이 있지만(선택한 답변 참조) 문제의 문제를 해결하는 내용을 찾을 수 없습니다.
나는 광범위하게 검색했습니다. 구글링(또는 duckduckgo-ed)을 통해 how to read a file in bash
얻은 모든 결과는 위 게시물에 따르면 확실히 bash 스타일이 아니므로 피해야 하는 솔루션을 가리켰습니다. 특히 다음과 같은 정보가 있습니다.
while read line; do
echo $line | cut -c3
done
이:
for line in `cat file`; do
foo=`echo $line | awk '{print $2}'`
echo whatever $foo
done
이는 쉘 스크립트의 매우 나쁜 예로 간주됩니다. 이 시점에서 저는 궁금합니다. 실제 질문은 다음과 같습니다. while 루프는 나쁜 습관이기 때문에 게시하지 말아야 할까요? 어떻게 해야 할까요?
편집: 이미 루핑의 정확한 문제를 다루는 의견/질문이 있다는 것을 알았 while
으므로 질문의 범위를 조금 확장하고 싶었습니다. 기본적으로, 나는 bash 명령을 더 깊이 파고들 필요가 있고 그것이 내가 실제로 해야 할 일이라는 것을 이해하고 있습니다. 그러나 사람들이 검색해 보면 일반적으로 사람들이 bash를 잘못된 방식으로 사용하고 가르치는 것처럼 보입니다(내 인터넷 검색에 따르면).
답변1
당신이 링크한 게시물의 요점은 이것을 설명하는 것입니다일반적으로 bash를 사용하여 텍스트 파일을 구문 분석하는 것은 좋지 않습니다.. 이는 특별히 루프 사용에 관한 것이 아니며 다른 컨텍스트의 쉘 루프에는 본질적으로 잘못된 것이 없습니다. while
쉘 스크립트에 대해 나쁜 말을 하는 사람은 없습니다 . 또 다른 기사에서는 텍스트 파일을 구문 분석하기 위해 셸을 사용해서는 안 되며 다른 도구를 사용해야 한다고 말했습니다.
명확히 하자면, "쉘 사용"이란 쉘의 내부 도구를 사용하여 파일을 열고, 데이터를 추출하고, 구문 분석하는 것을 의미합니다. 예를 들어 다음과 같습니다.
while read number; do
if [ $number -gt 10 ]; then
echo "The number '$number' is greater than 10"
else
echo "The number '$number' is less than or equal to 10"
done < numbers.txt
답변을 읽어주세요쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?이런 종류의 행동이 왜 나쁜 생각인지 자세히 알아보세요. 여기서는 이 글이 일반적으로 쉘 루프에 반대하는 것이 아니라 쉘 루프(또는 쉘)를 사용하여 파일을 구문 분석하는 것에 반대한다는 점을 분명히 하겠습니다.
bash를 사용하여 이 작업을 수행하는 더 좋은 방법에 대한 제안을 찾지 못한 이유는 bash나 다른 쉘을 사용하여 이를 수행할 수 있는 좋은 방법이 없기 때문입니다. 무엇을 하든 셸을 사용하여 텍스트를 구문 분석하는 것은 느리고 번거로우며 오류가 발생하기 쉽습니다.
셸은 주로 컴퓨터에서 실행할 명령을 입력하는 방법으로 설계되었습니다. 스크립트 언어로 사용할 수 있지만 실행 명령을 내릴 때 가장 잘 작동합니다.아니요그것을 사용할 때대신에텍스트 구문 분석을 처리하도록 설계된 명령입니다.
쉘은 다른 도구와 마찬가지로 도구이므로 설계된 목적에 맞게 사용해야 합니다. 문제는 많은 사람들이 쉘 스크립팅을 조금 배웠기 때문에 "해머"라는 도구를 가지고 있다는 것입니다. 그들이 아는 것은 망치뿐이기 때문에 그들이 직면하는 모든 문제는 그들에게는 못처럼 보이며, 그들은 그 못을 망치로 박으려고 합니다. 불행히도 텍스트 구문 분석은 쉘이 처리하도록 설계된 것이 아니며 "못"이 아니므로 "해머"를 사용하는 것은 좋은 생각이 아닙니다.
그래서 "bash에서 파일을 어떻게 읽어야 하나요?"에 대한 대답은 매우 간단합니다. "bash를 사용하지 말고 작업에 적합한 도구를 사용해야 합니다."
답변2
귀하의 예에서 피하고 싶은 것은 루프가 아니라 명령에 대한 다중 호출의 무의미한 사용입니다. 루프는 쉘 스크립트에서 쓸모없는 명령 호출의 가장 일반적인 이유 중 하나입니다(또 다른 큰 이유는 리디렉션 사용을 기억하지 못하는 것입니다).
새 프로세스를 시작하는 것은 거의 모든 시스템에서 가장 비용이 많이 드는 작업 중 하나이므로 효율적인 스크립트(및 일반적으로 효율적인 코드)는 총 프로세스 수를 최소로 유지할 수 있습니다. 이러한 효율성 제한은 inetd
그것이 선호되지 않는 주된 이유이며, 많은 웹 서버가 기본적으로 수요에 따라 각 연결에 대해 프로세스를 생성하는 대신 수명이 긴 여러 프로세스를 시작하고 요청에 따라 연결을 제공하는 이유입니다.
두 예제 모두 다음으로 시작하여 단순화할 수 있습니다.하나의전체 운영 과정. 따라서 첫 번째는 다음과 같습니다.
cut -c3
두 번째는 다음과 같습니다.
awk '{print $2}'` < file
이는 더 효율적일 뿐만 아니라 더 읽기 쉽습니다.
루프가 일반적으로 나쁘다는 것은 아니지만, 관련된 도구가 본질적으로 여러 줄이나 파일을 처리하기 때문에 다른 언어의 루프로 수행할 수 있는 많은 작업이 쉘 스크립트에서 필요하지 않다는 것입니다. 좋은 예회의이를 사용하는 유효한 목적은 무언가를 수행하려는 여러 시도를 처리하는 것입니다("무언가"가 본질적으로 재시도를 지원하지 않는다고 가정).
답변3
호출하는 쉘 while
이나 for
루프를 사용하는 대신awk
한 줄에 한 번씩, 파일 이름을 인수로 전달하여 awk를 한 번 실행하세요. 예를 들어
awk '{print "whatever " $2}' file
cut
같은
cut -c3 file
추가 처리가 필요한 경우배쉬에서awk가 반환한 각 줄에서 가장 좋은 옵션은 다음을 사용하는 것입니다.명령 대체배열을 채웁니다.
myarray=( $(awk '{print $2}' file) )
중요한 것은 무엇인가아니요여기서는 큰따옴표로 명령 대체를 인용합니다.생각하다쉘은 단어 분할을 수행합니다. 배열의 각 요소는 "단어"가 되며 awk의 입력은 공백으로 구분되고 하나의 필드만 인쇄하므로 각 줄은 하나의 "단어"를 출력합니다.
또는 내장된 readarray
bash를 사용할 수도 있습니다.mapfile
프로세스 교체:
mapfile -t myarray < <(awk '{print $2}' file)
입력에 $2와 같은 glob 패턴이 포함된 경우 mapfile
/variant가 필요합니다. 그렇지 않으면 쉘이 glob을 확장하려고 시도합니다.readarray
*
배열에 데이터가 있으면 for 루프를 사용하여 반복할 수 있습니다. 예를 들면 다음과 같습니다.
for i in "${myarray[@]}"; do do_something_with "$i"; done
또는 다른 프로그램이나 내장에 매개변수로 전달합니다.
printf "whatever %s\n" "${myarray[@]}"
그러나 추가 처리는 awk에서 수행하는 것이 거의 항상 더 좋습니다. 이는 대부분의 작업이 awk에서 완료되도록 bash 스크립트를 다시 디자인하고 다시 작성하는 것을 의미할 수 있습니다. 또는 bash가 필요하지 않은 것으로 판명되면 전체를 awk 스크립트로 다시 작성하세요. 펄도 마찬가지다. 그리고 파이썬. 그리고 다른 언어.
쉘은 훌륭한 프로그래밍 언어이다다른프로그램은 데이터를 처리하고 실제 작업을 수행할 수 있지만 데이터 처리 작업 자체를 수행하는 데는 형편없습니다. 거의 모든 다른 언어가 셸보다 데이터 처리에 더 적합합니다.
쉘과 awk 또는 다른 언어 사이에서 데이터를 앞뒤로 이동하는 경우 이는 전체를 awk(또는 다른 언어)로 다시 작성해야 한다는 좋은 신호입니다.
답변4
나는 실용적인 관점에서 이 답변을 작성합니다. Bash에서 루프를 사용하는 것이 반드시 나쁜 것은 아니라고 생각합니다.
Bash와 같은 스크립팅 언어를 사용할 때의 가장 큰 장점 중 하나는 염두에 두고 있는 작업을 최대한 빠르고 쉽게 달성할 수 있다는 것입니다. Bash는 파이프를 통해 작고 효율적인 범용 프로그램(예: cat, cut, head, grep, tee 등)을 결합할 수 있도록 하여 이를 수행합니다. 사람들은 grep <something> input-file | cut -c3
동일한 작업을 수행하고 대부분의 경우 훨씬 더 느린 프로그램을 처음부터 작성하는 것보다 이미 효율적인 프로그램 세트(예: )를 활용하기 위해 Bash 한 줄짜리를 사용하는 것을 선호합니다 .
Bash가 제공할 수 있는 것에 대한 일반적인 아이디어가 있다면, 즉 기본 Unix 프로그램, Bash의 파이프 기능 및 프로그래밍 언어 구성에 대해 충분히 알고 있다는 의미이며 루프 사용이 여전히 편리하다면 그것을 선택하십시오.