for 루프 출력의 파이프라인은 지역 변수 수정을 방지합니다.

for 루프 출력의 파이프라인은 지역 변수 수정을 방지합니다.

여러 파일 및/또는 디렉터리를 인수로 받아들이는 간단한 bash 함수를 작성하려고 합니다. 그것은 다음과 같아야 합니다:

  1. 정규화된 파일 이름입니다.
  2. 정렬하세요.
  3. 중복된 항목을 제거하세요.
  4. 실제로 존재하는 모든 것을 인쇄하십시오.
  5. 존재하지 않는 파일 수를 반환합니다.

내가 원하는 것을 거의 수행하는 스크립트가 있지만 정렬에 있어서는 실패합니다. 스크립트의 반환 값은 현재 정확하지만 출력이 올바르지 않습니다(정렬되지 않고 중복됨). 지시에 따라 명령문의 주석 처리를 제거 하면 | sort -u출력은 정확하지만 반환 값은 항상 입니다 0.

참고: 문제에 대한 더 간단한 해결책은 환영하지만 문제는 실제로 내 코드에서 이런 일이 발생하는 이유에 관한 것입니다. 즉, 파이프를 추가하면 스크립트가 변수를 증가시키지 못하는 것처럼 보이는 이유는 무엇입니까 r?

스크립트는 다음과 같습니다.

function uniqfile
{
    local r=0 

    for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done #| sort -u    ## remove that comment

    return $r
}

답변1

이것은 잘 알려진 배쉬 트랩입니다.특징:

파이프라인의 각 명령은 별도의 프로세스(즉, 하위 셸에서)로 실행됩니다.

이러한 수정된 변수는 하위 쉘에 로컬이며 상위 쉘로 반환되면 표시되지 않습니다.

이를 방지하려면 파이프를 피하고 프로세스 대체를 수행하도록 코드를 다시 작성하십시오.

 for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done > >(sort -u)

답변2

| sort -u이전 비트(따라서 전체 for 루프)가 하위 프로세스에서 실행되도록 강제합니다 (bash에서는 "STDIN"으로 리디렉션하려면 "STDOUT"이 필요합니다. (인터넷에서는 sort이 상황을 약간 다르게 생각 ksh하고 처리하는 것 같습니다 bash... 명령은 다음과 같습니다.) 파이프라인 시퀀스에서 서브셸에 먼저 넣을 것인가 아니면 마지막에 넣을 것인가?)

이 스레드에서는 비슷한 문제를 논의하고 마지막에 깔끔한 해결책을 제공합니다.http://ubuntuforums.org/showthread.php?t=312017

발췌
    #!/bin/bash
    exec 3< <(du | sort -n)  

    n=0
    while read size dir; do
      [ $size -gt 1000 ] && ((n++))
    done <&3
    exec 3<&-

    echo "Found $n too big files"

관련 정보