질문

질문

상태 코드가 쓸모없을 때 stdout 출력에서 ​​파이프라인을 구축하는 방법이 있나요?

답변이 사용 사례를 다루지 않고 쉘 스크립트 범위 내의 문제를 다루기를 바랍니다. 내가 원하는 것은 국가와 언어 코드를 기반으로 이름을 추측하여 저장소에서 사용 가능한 가장 구체적인 패키지를 찾는 것입니다.

예를 들면 다음과 같습니다.

  • $PACKAGE1=hunspell-en-zz
  • $PACKAGE2=hunspell-en

첫 번째 추측이 더 적합하지만 존재하지 않을 수도 있습니다. 이 경우 첫 번째 옵션 ( )이 반환하기 때문에 hunspell-en( )를 반환하고 싶습니다.$PACKAGE2hunspell-en-zz$PACKAGE1아니요존재하다.

적절한 캐시 파이프라인

문서에서 명령을 실행할 수 있는 한 명령은 apt-cache성공을 반환합니다(셸에서 종료 코드 0으로 정의됨).apt-cache

apt-cache는 정상 작동 중에는 0을 반환하고 오류가 발생하면 십진수 100을 반환합니다.

이로 인해 파이프라인에서 명령을 사용하는 것이 더 어려워집니다. 일반적으로 404에 해당하는 패키지 검색에서는 오류가 발생할 것으로 예상합니다( curlOR 과 마찬가지로 wget). 패키지가 존재하는지, 존재하지 않는지 검색하고 싶습니다.다른 패키지가 있는 경우 다른 패키지로 대체.

첫 번째 명령이 성공을 반환하기 때문에 아무것도 반환하지 않습니다(따라서 실행 중인 rhs는 절대 실행되지 않습니다 ||).

apt-cache search hunspell-en-zz || apt-cache search hunspell-en

apt-cache search두 가지 매개변수가 있습니다.

apt-cache인수가 다음과 동일하기 때문에 아무것도 반환하지 않습니다 .

apt-cache search hunspell-en-zz hunspell-en

문서에서apt-cache

별도의 매개변수를 사용하여 및로 결합된 여러 검색 패턴을 지정할 수 있습니다.

따라서 이러한 매개변수 중 하나가 분명히 존재하지 않으므로 아무 것도 반환되지 않습니다.

질문

apt-cache반환 코드가 작업에 유용하지 않은 경우 규칙을 처리하기 위한 쉘 관용구는 무엇입니까? 성공은 STDOUT의 출력 여부에만 달려 있습니까?

~처럼

  • 아무것도 발견되지 않을 때 찾기가 실패하도록 만들기

    그것들은 모두 같은 문제에서 비롯됩니다. 불행하게도 여기서 선택한 답변에는 find -z적용되지 않는 솔루션이 언급되어 있으며 사용 사례에 따라 다릅니다. 널 종료를 사용하지 않고 관용구나 파이프 구성에 대한 언급이 없습니다(위의 옵션 아님 apt-cache).

답변1

명령을 받아들이고 출력이 있으면 true를 반환하는 함수를 만듭니다.

r() { local x=$("$@"); [ -n "$x" ] && echo "$x"; }

( ( r echo -n ) || echo 'nada' ) | cat      # Prints 'nada'
( ( r echo -n foo ) || echo 'nada' ) | cat  # Prints 'foo'

따라서 이 사용 사례에서는 다음과 같이 작동합니다.

r apt-cache search hunspell-en-zz || r apt-cache search hunspell-en

답변2

내가 아는 한, 명령의 성공 여부가 출력 여부에 따라 달라지는 상황을 처리하는 표준 방법은 없습니다. 그러나 해결 방법을 작성할 수 있습니다.

예를 들어 명령의 출력을 변수에 저장한 다음 변수가 비어 있는지 확인할 수 있습니다.

output="$(command)"

if [[ -n "${output}" ]]; then
  # Code to execute if command succeded
else
  # Code to execute if command failed
fi

나는 이것이 일반적인 질문에 대한 답이라고 생각하지만, apt-cache search몇 가지 해결책에 대해 이야기하면 그것이 떠오릅니다.

패키지 관리를 더 쉽게 해주는 스크립트가 있습니다. 그 기능 중 일부는 다음과 같습니다:

search() {
  local 'package' 'packages'
  packages="$( apt-cache search '.*' | cut -d ' ' -f '1' | sort )"
  for package; do
    grep -F -i -e "${package}" <<< "${packages}"
  done
}


search_all() {
  local 'package'
  for package; do
    apt-cache search "${package}" | sort
  done
}


search_description() {
  local 'package' 'packages'
  packages="$( apt-cache search '.*' | sort )"
  for package; do
    grep -F -i -e "${package}" <<< "${packages}"
  done
}


search_names_only() {
  local 'package'
  for package; do
    apt-cache search --names-only "${package}" | sort
  done
}

이를 통해 단일 명령으로 여러 검색을 수행할 수 있습니다. 예를 들어:

$ search hunspell-en-zz hunspell-en
hunspell-en-au
hunspell-en-ca
hunspell-en-gb
hunspell-en-med
hunspell-en-us
hunspell-en-za

각 함수는 데이터베이스를 다르게 검색하므로 사용하는 함수에 따라 결과가 달라질 수 있습니다.

$ search gnome | wc -l
538
$ search_all gnome | wc -l
1322
$ search_description gnome | wc -l
822
$ search_names_only gnome | wc -l
550

답변3

나는 그것을 우아하다고 부르지는 않지만 그것이 일을 한다고 생각합니다.

search_packages () {
    local packages=($@)
    local results=()
    for package in "${packages[@]}"; do
        results=($(apt-cache -n search "$package"))
        if [[ "${#results[@]}" -eq 0 ]]; then
            echo "$package not found."
        elif [[ "${#results[@]}" -eq 1 ]]; then
            do stuff with "$package"
        else
            echo "Warning! Found multiple packages for ${package}:"
            printf '\t-> %s\n' "${results[@]}"
        fi
    done
}

불행하게도 테스트할 데비안 컴퓨터가 없습니다. 검색하려는 내용이 거의 확실해 보이므로 검색 결과를 제한하기 -n위해 "이름만" 옵션을 추가했습니다 .apt-cache

다음과 같이 실행할 수 있습니다.

$ search_packages hunspell-en-zz hunspell-en
$ my_packages=('hunspell-en-zz' 'hunspell-en')
$ search_packages "${my_packages[@]}"

답변4

다음 중 하나를 정의할 수 있습니다.

has_output() {
  LC_ALL=C awk '1;END{exit!NR}'
}

그런 다음:

if cmd | has_output; then
  echo cmd did produce some output
fi

일부 awk구현에서는 입력에서 NUL 문자를 차단할 수 있습니다.

대조적으로 grep '^'위의 내용은 개행으로 끝나지 않는 입력에 대해 작동이 보장되지만 누락된 개행을 추가합니다.

이를 방지하고 awkNUL 차단 시스템으로 포팅하려면 다음을 사용할 수 있습니다 perl.

has_output() {
  perl -pe '}{exit!$.'
}

를 사용하면 perl임의의 파일을 보다 우아하게 처리하는 변형을 정의할 수도 있습니다.

has_output() {
  PERLIO=:unix perl -pe 'BEGIN{$/=\65536} END{exit!$.}'
}

이는 메모리 사용량을 제한합니다(예: 대용량 스파스 파일과 같이 개행 문자가 없는 파일의 경우).

다음과 같은 변형을 만들 수도 있습니다.

has_at_least_one_non_empty_line() {
  LC_ALL=C awk '$0 != "" {n++};1; END{exit!n}'
}

또는:

has_at_least_one_non_blank_line() {
  awk 'NF {n++};1; END{exit!n}'
}

(정의에 주목하세요공백구현은 다양하며 awk일부는 공백과 탭으로 제한되고 일부는 CR 또는 FF와 같은 ASCII 세로 간격 문자도 포함하며 일부는 로케일 공백을 고려합니다.

이상적으로는 Linux에서는 splice()시스템 호출을 사용하여 성능을 최대화하는 것이 좋습니다. 이를 노출하는 명령은 모르지만 언제든지 python's를 사용할 수 있습니다 ctypes.

has_output() {
  python -c 'if 1:
    from ctypes import *
    import sys
    l = CDLL("libc.so.6")
    ret = 1
    while l.splice(0,0,1,0,65536,0) > 0:
      ret = 0
    sys.exit(ret)'
}

( has_output이 작업을 수행하려면 stdin 또는 stdout(또는 둘 다)이 파이프여야 합니다 splice().)

관련 정보