`locate` の結果の 1 つを選択して、指定したアプリケーションで開くようにするにはどうすればよいでしょうか

`locate` の結果の 1 つを選択して、指定したアプリケーションで開くようにするにはどうすればよいでしょうか

という bash スクリプトがありfindme、次のようにコード化されています。

#!/bin/bash
locate -Abi '*\.'$1 $2 | grep --color=always -ni $2 | less -R

指定されたファイル拡張子 (スクリプトに指定された最初の引数) を持ち、ファイル名にパターン (次に指定された引数) が含まれるすべてのファイルを検索します。
以下を実行すると:

user@machine$ findme pdf classifi

pdfファイル名に含まれるすべてのファイルを検索しますclassifi。そのため、次のような結果が得られます。

1:/home/user/Dropbox/SharedWithFriends/math/分類するcations2000.pdf
2:/home/user/Dropbox/SharedWithFriends/math/分類するcations2010.pdf

質問は: 「結果を表示した後に数値とビューアを要求し、次のジョブを自動化する bash スクリプト コードを教えていただけますか?」

たとえば、次のように入力するとします。

> 2 evince

スクリプトは検索結果の2番目の項目evinceで実行されます。2つまり前回の検索結果で入力したものがこれであれば、次のように実行されます。

evince /home/user/Dropbox/SharedWithFriends/math/classifications2010.pdf

答え1

これは、結果を表示する関数のバリエーションですが、結果に番号を付けたりページ付けしたりfindmeする代わりに、内部配列から結果をリストし、項目とプログラムの選択を要求します。grepless

#!/usr/bin/env bash

readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2" | grep --color=always -i "$2")

for((i=1; i <= ${#results[*]}; i++))
do
  printf "%d: %s\n" $i "${results[i]}"
done
read -p "> " item program
$program "${results[item]}"

ファイル名や grep パラメータ内のスペースをより適切に処理するために、元のスクリプトに引用符を追加しました。呼び出しを調整してreadarray、結果が 0 ではなくインデックス 1 から始まるようにし、grep の番号付けに対応させました。

答え2

findmeスクリプトにはいくつか問題があることに注意してください。

  • 変数置換の二重引用符が抜けている
  • の出力は、grep --color=alwaysコマンド置換で使用できない結果を生成します。 を通過させる必要がありますlessが、スクリプトで再利用しないでください。
  • grep と locate は異なるパターン構文を使用するため、grep2 番目の引数に color を使用しても常に機能するとは限りません。 を渡す-rlocate正規表現が使用されますが、grep がサポートする構文とは少し異なる Emacs 構文が使用されます。

bashでは、mapfile確実に配列にいくつかの行を詰め込むことができます。これと組み合わせるとプロセス置換コマンドの出力を使用します。次に、その配列を印刷し、ユーザーの入力を読み取ります。

findrun () {
  mapfile search_hits <(locate -Abir ".*\.$1" "$2")
  print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2"
  if read -a cmd; then
    set -- "${cmd[@]}"
    set -- "$@" "${search_hits[$1]}"
    shift
    "$@"
  fi
}

代わりのインターフェースは位置パラメータを設定することです。関数から位置パラメータを変更できないので少しトリッキーですが、bashでそれを実行する回りくどい方法エイリアスを使用してスクリプトをソースします。引用には注意してください。

alias findrun='. <(echo findrun_prepare \"\$@\"; echo set -- "\"\${search_hits[@]}\"")'
findrun_prepare () {
  mapfile search_hits <(locate -Abir ".*\.$1" "$2")
  print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2" >&2
}

使用法:

findrun pdf classifi
evince "$2"

答え3

Jeff Schaller が提示したソリューションに基づきます。解決策を見つけました。より良いものにするために、皆さんのコメントをいただければ幸いです。

#!/bin/bash

readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2")

for((i=1; i <= ${#results[*]}; i++))
do
  printf "%d: %s" $i "${results[i]}" | grep --color=always -i "$2"
done

read -p "> " item program

$program "${results[item]}"

これは、(トピックの複雑さに応じて)単純な答えのように見えます。

しかし、結果が特定の数を超える場合は十分ではありません。その場合は、次のようなものが必要ですmoreless

関連情報