web-dev-qa-db-ja.com

ユーザーが出力したlsを並べ替える

Linuxでは、ユーザーによるls出力の並べ替えにする方法はありますか?私が達成しようとしているのは、次のようなものです。

user _a file1
user _a file2
user _b another_file
user _c this_file
user _c that_file
user _d file3

このようなリストには、ファイルサイズ、権限なども含まれることを認識しています。私の主な関心事は、ユーザーによる並べ替えです。とても便利だろうね

これまでのところ、[ls -l | sort -k 3を使用している場合]にファイル所有者が含まれている列3で並べ替えるls -lが見つかりました[したがって、グループで並べ替えるsort -k 4]。

[〜#〜] but [〜#〜]ファイル所有者が3行目にない場合はどうなりますか? 列の数に関係なくこれを達成するに別の方法はありますか?


更新:言及するのを忘れました私はBASHで働いていますそして、物事がより複雑にならないように、これからかなり長い間それに固執しようとします。

3
erch

どちらが不可能かを知らずに、単一のls -l出力から所有者名がどの列にあるかを判別します。各列のエントリをpasswdファイルと一致させようとすることもできますが、/etc/passwdで見つかった名前しか含めることができないグループ列またはファイル名列の両方と一致しないという保証はありません。

lsを使用する場合は、プログラムを2回実行できます。1回はls -lとして、もう1回はls -gとして実行できます。後者は所有者を削除するため、他の情報に基づいて行を照合することにより、指定なしで所有者名を判別できます。ただし、これはbashシェルスクリプトで実行したい演習ではありません。

3
Anthon

zshを使用すると、並べ替え順序を定義して、次のようなグロブ修飾子で使用できます。

zmodload zsh/stat
uid() zstat -A REPLY +uid -- $REPLY

... *(no+uid)

(番号順の場合はnorderの場合はouid関数で注文する場合は+uid)。アイデアは、$REPLYのファイル名を受け取り、zshがソートする$REPLYの何かを返す関数を持つことです。

したがって、たとえばGNU ls

ls -ldU -- *(no+uid)

GNUツールのみの場合、同等のものは次のようになります。

find . ! -name . -Prune -printf '%U\t%p\0' |
  sort -zn |
  tr '\0\n' '\n\0' |
  cut -f2- |
  tr '\0\n' '\n\0' |
  xargs -r0 ls -ldU
3

lsを解析しないでください :使用 stat

stat -c "%U %n" -- * | sort
3
glenn jackman

OPは特定の移植性要件(Bashでの使用を除く)を規定しておらず、 lsの解析 が引き続き一般的なアプローチであるように思われるため、またstatベースのソリューションはファイル名の改行をうまく処理できないようです(とにかく、誰がファイル名に改行を入れますか?)、私は最もエレガントな解決策のために私自身の提案を投げかけるつもりです:

OPが実際にほぼ最良の答えを持っていたと思います。予期しない動作によるエイリアシングを防ぐために、エスケープする必要があります(これはBash固有のソリューションであることを忘れないでください)。

\ls -l | sort -k 3

18文字で、lssortのみが必要で、ループは必要ありません。エレガントで、理解しやすく、信頼性があります。

また、Olivierが彼の回答で指摘したように、sortを、その列で始まる行全体ではなく、3番目の列のみに制限することが望ましい場合があります。

\ls -l | sort -k 3,3

3番目の列に所有者が含まれていないls -lの実装、または他の回答で与えられたソリューションを壊さないこのソリューションを壊す方法を誰かが見つけた場合、この回答を撤回します。

2
depquid

1)どの列が名前であるかを判別します。

myls='ls -al'
echo '+' > /tmp/MYOWNFILE.$$  #so file will be of size 2, "+" and newline.
zeuser=$( $myls /tmp/MYOWNFILE.$$ | awk -v myname=$(whoami) '{ for (field=1;field<=NF;field++) { if ($field == myname) { print field ; break } } }' )
zesize=$( $myls /tmp/MYOWNFILE.$$ | awk '{ for (field=1;field<=NF;field++) { if ($field == 2) { print field ; break } } }' )
zename=$( $myls /tmp/MYOWNFILE.$$ | awk -v filename=/tmp/MYOWNFILE.$$ '{ for (field=1;field<=NF;field++) { if ($field == filename) { print field ; break } } }' )
rm /tmp/MYOWNFILE.$$

ユーザー名を示す列を変数zeuserに配置します
サイズを保持するzesize = column、およびファイル名を保持するzename = columnも決定します

Lsコマンドを変数に入れるので、列を決定する行は、後で使用される実際のコマンドを使用します(変更して、リストされている列を変更する場合)

2)並べ替えを使用してその列を並べ替えます。

$myls | sort -k${zeuser},${zeuser}  #sort ONLY on column of usernames (see last example for bad alternative)
$myls | sort -k${zeuser},${zeuser} -k${zename},${zename} #sort on user, and then on filename
$myls | sort -k${zeuser},${zeuser} -k${zesize},${zesize}nr #sort on user, 
                            #  and then on size 
                            #modifiers: 'n'=order Numerically (and not alphabetically), 
                            #           'r'=Reverse order
$myls | sort -k${zeuser}    #sort STARTING FROM user column, which is probably not what you want!
                     #indeed the next column is probably the group, then the size...
                     #It will be sorting in a not so usefull way (especially as the
                     #  size will be sorted alphabetically instead of numerically)
1
Olivier Dulac

これがあなたのためにそれをするべきである小さな1つのライナーです:

\ls -l | sort -k$(for i in {1..5}; do field=$(\ls -ld ~ | cut -d' ' -f$i); if [ x$field = x$(whoami) ]; then echo $i; break; fi; done)

ホームディレクトリで実行されたls -lの各フィールドを、ユーザー名に一致するフィールドが見つかるまでウォークスルーし、その番号を-kオプションに置き換えてsort

私はあまり専門家ではないので、これのいくつかはbashバージョンまたはGNU固有ですが、私のマシンでは正常に動作します。

1〜5を選択したのは、ユーザーを見つけるために必要な範囲であるためです。特にls -ld ~の出力を毎回呼び出すのではなく文字列に保存した場合は、より多くの数値を使用できます。結果を配列に格納してそのように参照すると、さらに最適化できる可能性があります。しかし、これは頭のてっぺんから離れて、素早く汚いものでした。

0
Drake Clarris