部分名でファイル範囲を選択する方法

部分名でファイル範囲を選択する方法

ファイル名の一部を使用してコピー、移動などのファイル範囲を選択したいと思います。

ランダムな例のリスト:

  1. α1a
  2. α2aa
  3. alpha3abc
  4. ブラボーA1
  5. ブラボー B2bb
  6. 白人
  7. DeltaA1FDFD
  8. DeltaA2 ダパ
  9. デルタA2222
  10. δC1
  11. ...(他のファイルの束)

alpha2*からdeltaA*までいくつかのコマンドを実行したいと思います。これにより、リストから2〜9が選択されます。これにより、実際にファイルがいくつあるか心配せずに名前に基づいて範囲を選択でき、追加のコンテンツも取得できません。

答え1

start=alpha2*
end=deltaA*

for file in *
do
    if [[ $file > $start && ( $file < $end || $file == $end ) ]]; then
        echo $file
    fi
done

エコーの代わりに配列にファイルを保存できます。

array+=($file)

次に、配列を使用してファイルをコピー、移動、または単にforループでコマンドを実行します。

答え2

シェルプログラミングは事前編成比較にはあまり良くありません。 Bash、ksh、またはzshで使用できます< 条件付き演算子2つの文字列を比較します(POSIX shには数値比較のみがあります)。

run_in_range () {
  start_at="$1"; end_before="$2"; command="$3"; shift 3
  for item do
    if [[ ! ($x < $start_at) && ($x < $end_before) ]]; then
      "$command" "$item"
    fi
  done
}
run_in_range alpha2 deltaB some_command *

最初の除外項目を2番目の引数として使用することに注意してください。は、でdeltaB始まるすべての文字列に続く最小の文字列ですdeltaAdeltaAパラメータとして渡したい場合は、これを行うことができます。

run_in_inclusive_range () {
  start_at="$1"; end_on_prefix="$2"; command="$3"; shift 3
  for item do
    if [[ ! ($x < $start_at) && ($x < $end_on_prefix || $x == "$end_on_prefix"*) ]]; then
      "$command" "$item"
    fi
  done
}
run_in_inclusive_range alpha2 deltaA some_command *

このコードはワイルドカードの順序には依存しません。アイテムのリストがソートされていない場合でも機能します。これにより、コードがより強力になりますが、リスト全体を繰り返す必要があるため、少し遅くなります。

これはPOSIX機能にのみ依存する代替方法です。sort文字列の比較に使用されます。これはプロジェクトに改行文字がないと仮定します。この機能はデフォルト設定を復元してグローブしますIFS(環境設定の復元は可能ですが、面倒になりにくい)。

run_in_range () {
  IFS='
'; set -f
  start_at="$1"; end_before="$2"; command="$3"; shift 3
  set $({
          printf '%s1\n' "$@"
          printf '%s0\n' "$start_at" "$end_before"
        } | sort | sed '/0$/,/0$/ s/1$//p')
  unset IFS; set +f
  for item do
    "$command" "$item"
  done
}

説明する:

  1. 1追加項目と追加の境界を使用してリストを整理します0
  2. リストを並べ替えます。
  3. 2つの境界線(で終わる行0)の間の行を印刷しますが、で終わる行1(つまり項目)のみを印刷し、末尾1

答え3

私の考えでは、この問題はビューよりも解決するのが簡単です。

1行にファイルを1つずつリストを取得する方法があるとします。
現在のディレクトリの場合:

list="$(printf '%s\n' *)"

リストに制限を追加して並べ替えるだけです。

nl='
'
lim1="alpha2"
lim2="deltaA"

echo -- "$list""$nl""$lim1""$nl""$lim2" | sort

次に、lim1で印刷を開始し(lim1とlim2は既存のファイル名と一致しません)、lim2で停止します。

また、簡単にするには、印刷したいファイルの前に最も短い文字列を選択し、選択する必要がある最後のファイルの後にソートされた最も短い文字列を選択します。

有用なのは排他的なリスト(制限を含まないリスト)ですが、
2つのソリューションを提供します。

デフォルト値:

list="$(printf '%s\n' *)"

lim1=alpha2
lim2=deltaA

awkを使用してリストを含むソリューションを入手してください。

echo "awk----------------inclusive"
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    awk -v lim1="$lim1" -v lim2="$lim2" '$0==lim1,$0==lim2{print}'

awkを使用して独自のリストを取得するソリューション:

echo "awk----------------exclusive"
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    awk -v lim1="$lim1" -v lim2="$lim2" '$0==lim1{p=1;next};$0==lim2{p=0};p'

リストを含むシェルを使用したソリューション:

echo "shell---------------inclusive"
show=0
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    while IFS="$nl" read -r line; do
        [ "$line" = "$lim1" ] && show=1
        [ "$show" = "1"     ] && printf '%s\n' "$line"
        [ "$line" = "$lim2" ] && show=0
    done

シェルのための排他的なソリューション:

show=0
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
    while read -r line; do
        [ "$line" = "$lim2" ] && show=0
        [ "$show" = "1"     ] && printf '%s\n' "$line"
        [ "$line" = "$lim1" ] && show=1
    done

関連情報