Bash - globを使用してリバースファイルリストを印刷する

Bash - globを使用してリバースファイルリストを印刷する

globでファイルリストを元に戻す方法はありますか?

したがって、次のような結果が得られます。

ls -r *

シェルスクリプトでこれを使用していますが、文句を言い続けますshellcheck

^---------^ SC2045: 繰り返し ls 出力が脆弱です。グローバルを使用してください。

答え1

扱いにくい

シェルを使用すると、(順序)、(逆と同じ)、および(数値の場合)glob修飾子を使用してzshglobのソート順序をカスタマイズできます。oCOC^oCn

引用するinfo zsh qualifier

oC

ファイル名のソート方法を指定します。 Cの場合は名前でソートされ、n ファイルLのサイズ(長さ)でソートさlれます。変更またはinodeの変更がある場合、サブディレクトリのファイルは、すべての検索レベルで現在のディレクトリのファイルの前に表示されます。これは、同じディレクトリ内のファイル名をソートするために ""などの他の条件と組み合わせて使用​​するのが最善です。ソートが実行されます。 、、、ageは現在時刻と比較されるため、リストの最初の名前は最も若いファイルです。また、修飾子とが使用されるため、 ''はシンボリックリンクの直後にファイルサイズの降順ですべてのファイルのリストを提供します。使用しない限り、複数の順序指定子が関係を解決しているように見えることがあります。amcdodonNamc^-*(^-oL)oN

glob修飾子を使用しない限り、デフォルトのソートはn(名前に基づいて)であり、この場合は(ソートされていません)です。YN

oeそしてo+特別なケースです。それぞれの後には、eglob修飾子とglob修飾子で+区切られたシェルコードが続きます(上記を参照)。コードは一致する各ファイルに対して実行され、パラメータはREPLYエントリのファイル名に設定され、コードは任意の方法でパラメータを変更する必要がありますglobsort。戻り値は、ファイル名の代わりに引数値をソートする文字列として使用します。他のソート演算子とは異なり、およびは繰り返すことができますが、すべてのglob式に表示できるすべてのタイプのソート演算子の最大数は12です。zsh_eval_contextREPLYoeo+

したがって、アルファベットの逆順でファイルのリストを取得するには、次のようにします。

list=(*(NOn))

または

list=(*(N^on))

N((for)修飾子はここでも使用されるため、nullglob一致するファイルがない場合はリストが空になります。)

変更時間に基づいて逆順にソートされたリストの場合(例ls -rt:):

list=(*(NOm))

oOzshを使用すると、パラメータ拡張フラグを使用して配列要素を並べ替えることもできます。

list=(*(N))
list_reversed=(${(Oa)list})

つまり、配列メンバーを$list逆順に並べ替えます(大文字の使用のためOa

強く打つ

最新バージョンのbashシェルとGNUを使用すると、sort逆順に並べられたファイル名のリストを取得できます。

readarray -td '' list < <(
   shopt -s nullglob
   set -- *
   (($# == 0)) || printf '%s\0' "$@" | sort -rz)

readarray -td '' arrayNULで区切られたレコードのリストを配列に読み込みます。

GNU実装の場合、ls別のアプローチは次のとおりです。

eval "list=($(ls --quoting-style=shell-always -r))"

ここではls --quoting-style=shell-always、一重引用符を使用してファイル名を引用します(\'一重引用符の外に一重引用符自体を引用します)。

このアプローチも機能しますyash(すべてのファイル名がロケールで有効なテキストであると仮定します)。ただしksh93、この場合は変数を事前に配列として宣言する必要があります(使用)。それ以外の場合、出力が提供されない場合は複合として生成されます。代わりに、変数は配列変数ではありません。zshmkshksh93typeset -a listls$list

lsast-open実装もオプションをサポートしていますが、引用形式を--quoting-style=shell-always使用しているため、すべてのロケールで使用するのは安全ではありません。$'...'

POSIXとして

POSIXly、配列をsh反転するには、次のことができます。"$@"

eval "set -- $(awk 'BEGIN {for (i = ARGV[1]; i; i--) printf " \"${"i"}\""}' "$#")"

アイデアは、3つの要素があるset -- "${3}" "${2}" "${1}"ときに出力と同じawk出力を持つことです。"$@"

したがって、ファイルのリストを逆順に取得するには、次の手順を実行します。

set -- *
eval "set -- $(awk 'BEGIN {for (i = ARGV[1]; i; i--) printf " \"${"i"}\""}' "$#")"
echo file list:
printf ' - %s\n' "$@"

POSIXには、同等のオプション(発明)、zshのglob修飾子、またはksh93のglob演算子はshありません。現在のディレクトリに隠されていないファイルがない場合は、1つの要素しかないリストが生成されます。この問題を解決する一般的な方法は次のとおりです。nullglobzsh(N)~(N)*

set -- [*] *
case "$1$2" in
  ('[*]*') shift 2;;
  (*)      shift;;
esac

ここで、[*]「and」の組み合わせは*「a」と区別される*方法です。矛盾[*]にも拡張[*])とリテラル名のファイル*[*]にも拡張*)です。


とにかく、シェルが拡張を渡す方法lsなど、ソートするファイル名のリストを渡す場合は、オプションを使用して次のようにオプションの終わりを表示する必要があります。ls -r **-d--

ls -rd -- *

ただし、ファイル名は改行で区切られ、改行はファイル名のすべての文字と同じくらい有効であるため、この出力はまだ安定して後処理できません。

答え2

この質問は、ファイル名globbingパターンを再実装するのではなく、生成されたリストを反転することについて考えていますls -r

位置パラメータのグローバル一致結果を取得します。たとえば、次のようになります。

set -- *

その後、リストを逆に置き換えます。

names=()
for name do
    shift
    names[$#]=$name
done

namesこれにより、反転されたワイルドカードパターンの一致を含む名前の配列が作成されます*

位置引数(一致結果)を順番に繰り返し、各項目の反転リストの位置に挿入して反転を実行します。$#は位置引数(ワイルドカードパターンと一致)の数であり、そのリストから1つを削除し、各shift反復$#ごとに1ずつ減らすため、位置引数リストの先頭から配列の最後まで要素を挿入しますnames

names配列があれば印刷します。

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

...または必要なものをすべて実行してください。

これはいいえls -r *このコマンドと同様に、lsglobと一致するすべてのディレクトリの内容が一覧表示されます*

一致するものがない場合は、bashパターンを展開しないでください。アクティブ化時に名前と一致しないパターンを完全に削除するshopt -s nullglobシェルを設定するオプション。nullglob隠された名前を一致させるには、追加のシェルdotglobオプションを設定します。

答え3

どのシェルを使用しているのか言っておらず、英数字の昇順以外の操作を実行するシェルを見たことはありません。したがって、これを行うにはlssortまたは同様のものを使用する必要があります。バラよりシェルチェックウィキ繰り返しの出力がls脆弱な理由とそれを解決する方法基本的に注目すべき2つの主な問題があります。 1)ディレクトリが空のときにデフォルトでecho *印刷されます。*2) ファイル名にスペースが含まれている場合、入力内容の読み込みに混乱を招く可能性があります。 (1)の場合、bashを使用している場合はこのオプションを設定する必要がありますnullglob。 (2)の場合は、次の内容を作成したい場合があります。

ls -1r | while read filename; do
    ...
done

sh(もう一度言うが、bashまたはを使用すると仮定しますzsh。)

答え4

ほとんどのシェルに移植可能であり、1つのファイルでエラーを防ぎます(seq与えられたシェルのみを使用しprintfseteval

set -- *
[ $# -gt 1 ] && eval set -- "$(printf "\"\${%s}\" " $(seq "$#" -1 1))"
printf '%s '   "$@"

可能であれば、nullglob と failedglob を設定するのが妥当です。

関連情報