「find -regextype egrep」をエイリアスに設定

「find -regextype egrep」をエイリアスに設定

さて、正規表現を学び始めましたが、他の正規表現の代わりにどこでも正規表現を使う練習をしたいと思います。

拡張子を持つファイルを見つけようとしたときに、このような状況が発生しました。sh or md

$ find . regex ".*\.(sh|md)$"
.
./bogus.py
./cofollow.py
./data8.txt
./example.sh
./longest_word_2.sh
./posit_param.sh
./cobroadcast2.py

残念ながら、それは出力されます/bogus.py

BREルールを見つけて脱出しようとしました。()

$ find . -regex ".*\.\(sh|md\)$"
#get nothing return

一連の検索の最後に -regextype ソリューションを取得しました。正規表現 - ファイルの検索

$ find . -regextype posix-extended -iregex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh

$ find . -regextype egrep -iregex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
./table_regex_bat.md

さらに、優れたモジュラーソリューション

$ find -type f | egrep ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
./table_regex_bat.md

ただし、BSDには述部を使用してこれらの操作を実行するための近道があります-E

$ /usr/bin/find -E . -regex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh

私は私のコードと技術を移植可能にするためにGNUツールだけを使用することにしました。

そのため、「find -regextype egrep」というエイリアスを指定し始め、
残念ながらfindはパスで$ 1を取得しました。

どうすれば問題を簡単に解決できますか?

答え1

aliasパラメータを渡すために使用しないでください。移植性がなく、インタラクティブシェルでのみ便利です。代わりに関数を使用して、パラメータを目的のパスに渡してください。

regexFind() {
    (( "$#" )) || { printf 'Insufficient arguments provided \n' >&2; return 1; }
     find "$1" -regextype egrep -iregex ".*\.(sh|md)$"
}

関数を次のように呼び出します。

regexFind "/home/foo/bar"

また、結果に追加するには、bashglobファイルの独自の方法もあることに注意してください。機能するには、いくつかの拡張シェルオプションを有効にするだけです。このオプションを有効にし-s-u無効にします。

nullglob拡張されていないグローバル結果を有効な一致として無視できます。したがって、*.shandで終わるファイルを一致させたい場合は、*.md特定のディレクトリに移動して次のようにします。

shopt -s nullglob
fileList=(*.sh)
fileList+=(*.md)
shopt -u nullglob

そして、以下のように結果を印刷してみてください。ファイル名がトークン化されないようにするには、拡張子を引用することを忘れないでください。

printf '%s\n' "${fileList[@]}"

答え2

GNUのデフォルトの正規表現は、BREではなく、いくつかの古代バージョンのGNUの正規表現です(たとえば、BREとERE間のいくつかのハイブリッド、サポートされているが必要でサポートされています)findemacs+\(...\)|\|

BSD の場合、findデフォルトは BRE です。この-Eオプションを使用してEREを有効にすることができます。

alias efind='find -E'

または:

efind() { find -E "$@"; }

GNUは、オプションではなく述語を介してfindEREを有効にします。-regextype posix-extended述語は、ファイル名の後に(存在する場合)、オプションの後、または-regex使用の前に表示する必要があります。-iregex

GNUfind構文は次のとおりです。

find [options] [files] [predicates]
                      ^

したがって、その位置(表示された位置)に挿入する必要があります^

したがって、ラッパー関数またはスクリプトを定義するときにこの点を考慮する必要があります。すべてのオプションとファイル名をスキップして、-regextype posix-extendedその後に挿入してください。

efind() (
  found_predicate=false
  for arg do
    "$found_predicate" || case $arg in
      (-[LPDd]|-[OD]*) ;;  # skip options
      (-*|['()!'])
        set -- "$@" -regextype posix-extended
        found_predicate=true;;
    esac
    set -- "$@" "$arg"
    shift
  done
  
  exec find "$@"
)

その他の注意事項:

  • 最初の印刷はbogus.pyBREを使用したためではなく、述語ではなくファイル名として扱われますregex-regexregex
  • find . | egrep ...ファイルパスが複数行で構成される可能性があるため、無効です。 GNUツールまたは互換ツールを使用すると、NULで区切られたレコードを処理できますfind . -print0 | grep -zE ...tr '\0' '\n'または表示に使用される場合はパイプで接続)。

答え3

find . -type f \( -name '*.sh' -o -name '*.md' \)

findこれは正規表現マッチングをサポートする必要がないため、すべての実装に適用されます。

より柔軟にするには:

suffixfind () (
    dir=$1
    shift

    for suf do
        set -- "$@" -o -name "*.$suf"
        shift
    done
    shift

    find "$dir" -type f \( "$@" \)
)

同様のシェルで動作するこのヘルパーシェル関数は、sh最初のコマンドライン引数を選択して変数に入れますdir。次に、関数-name "*.<suf1>" -o -name "*.<suf2>" (etc.)のコマンドラインからすべてのファイル名サフィックスのリストを設定し、findそのリストを呼び出して$dir

こうして使えばいいと思います。

suffixfind /usr sh md txt

.sh名前で終わるか、パスの内または下にある.mdすべての一般ファイルを見つけます。.txt/usr

bash配列とローカル変数を使用してbash上記の内容をより詳細に変換する方法は次のとおりです。

suffixfind () {
    local dir=$1
    shift

    local names

    names=( -name "*.$1" )
    shift
    for suf do
        names+=( -o -name "*.$suf" )
    done

    find "$dir" -type f \( "${names[@]}" \)
}

GNUツールと移植性に関する言及については、Linux以外のシステムでもGNUツールを使用できますが、gツール名にプレフィックスが付いていることに注意してください。したがって、GNUはfindこれをシステムの基本的な実装とgfind区別することができます。find

したがって、「GNU移植可能な」方法は、gfind実際にGNUかどうかをテストする前に使用可能かどうかをテストする必要があります。これを行うまでは(おそらくステータスと出力を返すテストを通して)GNUを扱っているという事実は不便です。findfindfind --versionfind

関連情報