質問

質問

ステータスコードが役に立たないときにstdout出力でパイプラインを構築する方法はありますか?

回答がユースケースをカバーするのではなく、シェルスクリプトの範囲内の問題に対処することを願っています。私が望むのは、国と言語コードに基づいて名前を推測して、リポジトリで利用可能な最も具体的なパッケージを見つけることです。

たとえば、次のようになります。

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

最初の推測がより適切ですが、存在しない可能性があります。この場合、最初のオプション()が返すのでhunspell-en()を返したいと思います。$PACKAGE2hunspell-en-zz$PACKAGE1いいえ存在する。

適切なキャッシュパイプライン

ドキュメントでコマンドを実行できる限り、コマンドはapt-cache成功を返します(シェルは終了コード0として定義されています)。apt-cache

apt-cache は通常動作中は 0 を返し、エラーが発生した場合は 10 進数 100 を返します。

これにより、パイプラインでコマンドを使用することがより困難になります。通常、404に対応するパッケージ検索ではエラーが発生すると予想されます(curlORと同様wget)。パッケージが存在するか、存在しないかを検索したいと思います。他のパッケージがある場合は、他のパッケージに置き換え

最初のコマンドは成功を返すため、何も返されません(したがって実行中のrhsは決して実行されません||)。

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

apt-cache search2つのパラメータがあります。

apt-cache引数が次のとおりであるため、何も返しません。

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

ドキュメントからapt-cache

別々のパラメータを使用して、およびで結合された複数の検索パターンを指定できます。

したがって、これらのパラメータの1つは明らかに存在しないため、何も返されません。

質問

apt-cache戻りコードが操作に役立たない場合、ルールを処理するためのシェルイディオムは何ですか?成功はSTDOUTの出力かどうかにかかっていますか?

〜のように

  • 何も見つからないときに検索が失敗するようにする

    それらはすべて同じ問題に由来します。残念ながら、ここで選択した回答にはfind -z適用されない解決策が記載されており、ユースケースによって異なります。 NULL 出口を使用せず、イディオムやパイプ構成についての言及はありません(上記のオプションではありません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
}

残念ながら、テストするDebianコンピュータはありません。検索しようとしている内容がほぼ確実に見えるため、検索結果を制限するため-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()。)

関連情報