Bash 및 ksh 파이프

Bash 및 ksh 파이프

ksh 스크립트에 문제가 있습니다. FWIW 제가 극복할 수 없는 문제는 이런 구조를 사용할 때입니다.

command | while read VAR1 
do
   many.commands using $VAR1
done

나는 종종 내 스크립트가 while에 파이프된 모든 줄에 대해 반복되지 않는다는 것을 발견합니다. 이것을 테스트하기 위해 구조를 다음과 같이 변경했습니다.

command > /tmp/tempfile
cat -n /tmp/tempfile >&2
cat /tmp/tempfile | while read VAR1
etc

이는 출력에 많은 행이 있음을 증명합니다.

또한 do like 직후에 한 줄을 추가합니다.

echo DEBUGGING: $VAR1  >&2

이는 루프가 한 번만 실행된다는 것을 증명합니다. 정말 혼란스러워요.

항상 가능하지는 않은 해결 방법은 다음과 같습니다.

for X in $(cat /tmp/tempfile )
do
...
done

그러면 이것은 잘 작동합니다. 단, 제가 이 구조를 싫어한다는 사실은 명령줄에서 전체 입력 데이터를 확장한다는 의미입니다(하드 제한 포함).

bash는 ksh보다 이런 종류의 일을 더 잘 처리하는 것 같습니다. 특히 이는 읽기 호출이 실패했지만 루프를 실행하는 데 오랜 시간이 걸리는 경우 재시도하지 않는 것과 관련이 있을 수 있습니다.

그러나 Bash에는 "읽기" 기능이 내장되어 있지 않은 것 같습니다. 이는 대부분의 스크립트를 다시 작성해야 함을 의미합니다. 나는 종종 다음과 같은 큰 구조를 사용합니다.

command1 | command2 | while read SOMEVAR; do awk -F: "... long awk program" | sed "long sed program" ; done | sort -u | tail -1 | read FINAL_ANSWER

문제는 bash가 예상대로 FINAL_ANSWER의 결과를 가능한 한 빨리 삭제하는 /usr/bin/read를 사용한다는 것입니다. 확실한 해결책은 교체하는 것입니다.

| read FINAL_ANSWER

그리고

> /tmp/final_answer && FINAL_ANSWER="$(cat /tmp/final_answer)"

그렇다면... 이에 대해 더 자세히 설명해 줄 수 있는 스크립팅 전문가가 있습니까? 실제 스크립트는 클라이언트를 위해 개발된 민감한 솔루션의 일부이고 스크립트의 실제 세부 사항으로 인해 문제가 혼동되는 것을 원하지 않기 때문에 여기에 실제 스크립트를 의도적으로 게시하지 않았습니다.

나는 종종 "읽으면서 읽기" 형식을 사용합니다. 일반적으로 작동합니다. 사실 25년 동안 쉘 스크립트를 작성하면서 아무런 문제도 겪어본 적이 없습니다. 이제 문제가 생겼습니다. 매우 실망스럽습니다. 혼란스럽다.

처음에는 읽는 동안 입력의 첫 번째 줄만 받거나 전달한다고 생각했습니다. 하지만 스크립트를 계속해서 실행하면 입력 내용이 점점 더 깊어지는 상황을 발견했습니다. 특히 나한테는 뭔가가 있어

command | while read NEXT_ONE DONEFLAG
do
   if [ $DONEFLAG = "yes" ]
   then
       echo Already completed work for $NEXT_ONE
   else
       dowork $NEXT_ONE && set_flag $NEXT_ONE
   fi
done

스크립트를 실행할 때마다 dowork한 번씩 실행되는 것으로 나타났습니다. dowork몇 초 이상 걸리면 정확히 무엇인지는 중요하지 않습니다. 일종의 셸 파이프 시간 초과가 발생한 다음 나머지 입력이 사라집니다. Google에서는 dtksh가 이 문제를 해결할 수 있다고 말합니다. (분명히 읽기/쓰기 등을 다시 시도하는데, 충분히 읽을 수 없습니다.)

/usr/st/bin/dtksh에 dtksh가 있는 것을 확인했습니다.

누구세요? 나는 내가 모르는 쉘을 사용하는 것을 좋아하지 않지만 /usr/dt/bin/dtksh를 인터프리터로 사용하여 스크립트의 작은 부분을 아래 첨자로 분할하는 것이 좋습니다.

어떤 제안이 있으십니까?

편집: 해석기로서 ksh의 드롭인 대체품으로 bash를 사용할 수 없는 이유에 대한 예를 제공하려면 다음을 수행하십시오.

sol10-primary> # cat test.sh
#!/bin/ksh
echo hello| read VAR1
echo $VAR1
sol10-primary> # ./test.sh
hello
sol10-primary> # sed 's/ksh/bash/' <test.sh >test2.sh
sol10-primary> # chmod +x test2.sh
sol10-primary> # ./test2.sh

sol10-primary> #

답변1

귀하의 질문은 약간 목적이 없습니다. 핵심 부분인 ksh와 bash의 차이점에 대해 답변해 드리겠습니다.

스크립트와 관련하여 ksh와 bash 사이의 가장 큰 비호환성을 경험했을 것입니다. ATT ksh(ksh88 및 ksh93) 및 zsh는 상위 셸의 파이프라인에서 마지막(가장 오른쪽) 명령을 실행하는 반면, 다른 셸(Bourne, ash, bash, pdksh, mksh)은 하위 셸의 마지막 명령을 포함하여 모든 명령을 실행합니다.

다음은 간단한 테스트 프로그램입니다:

msg="a subshell"
true | msg="the parent shell"
echo "This shell runs the last command of a pipeline in $msg"

ATT ksh 및 zsh에서는 두 번째 할당이 msg상위 셸에서 수행되므로 파이프 뒤에 효과가 표시됩니다. 다른 셸에서는 이 할당이 하위 셸에서 수행되므로 첫 번째 할당은 상위 셸에 유지됩니다.

해결 방법은 파이프라인에서 나머지 스크립트를 실행하는 것입니다. 이는 데이터를 읽고 일부 처리를 수행하는 일반적인 관용어입니다.

output_some_stuff | {
  var=
  while IFS= read -r line; do
    var=$(process "$line")
  done
  use "$var"
}

당신은 가지고있는 것 같습니다ksh 버그가 발생했습니다.. 버그 없는 버전으로 업그레이드하는 것이 좋습니다. 그게 불가능하다면 시도해 보세요스테판 차젤라스의 솔루션. bash에서 스크립트를 실행할 수는 있지만 ksh를 직접 대체하는 것은 아니며 bash에 없는 ksh 기능이 많이 있습니다(그 반대도 마찬가지입니다). Bash와 ksh는 POSIX 코어 및 기타 핵심 기능(특히 배열 [[ … ]]및 선언된 함수의 로컬 변수) 에서만 호환됩니다 typeset.

로 호출될 때 kshbash보다 ksh에 더 가깝게 동작하는 zsh를 시도해 볼 수도 있습니다. 그럼에도 불구하고 비호환성이 발생할 수 있습니다.

관련 정보