部分的なファイル名に基づいて一意のファイルのみをリストします

部分的なファイル名に基づいて一意のファイルのみをリストします

たとえば、以下の出力のようなファイルがたくさんあります。すべての一意のファイル名のリストを取得しようとしていますが、「-」の右側の文字は無視します。ls -la | grep ....- | sort --uniqueいくつかのバリエーションを試しましたが、必要な出力が得られませんでした。

4855-00160880.psi
4855-00160980.ps
4855-00160980.psi
5355-00160880.ps
5355-00160880.psi
5355-00160980.ps
5355-00160980.psi
5855-00160880.ps
5855-00160880.psi
5855-00160980.ps
5855-00160980.psi
5855-00160A80.ps
5855-00160A80.psi

理想的には、次のような出力を表示したいです。

4855
5355
5855

答え1

以来本当に解析したくないls、これでうまくいくはずです:

find . -type f -maxdepth 1 -exec basename "{}" \; | cut -d'-' -f1 | sort -u

答え2

これはどうですか?

printf "%-4.4s\n" ????-* | uniq

シェルはワイルドカードをアルファベット順に展開し、その結果を引数として に渡しますprintf。フォーマット文字列は各引数を 4 文字に切り捨て、改行を追加します。これで、隣接する重複を削除する作業が残ります。

ハイフンの前の桁数がわからないが、見当がつく場合は、いくつかの候補をループすることができます。

for expr in '??' '???' '????' '?????'  # Quoted (!)
do
    printf "%-${#expr}.${#expr}\n" $expr-* |  # Unquoted!
    uniq
done

これはBashのみのパラメータ拡張 $[#var}文字列の長さを取得します$var

ループの初期化中にワイルドカードが拡張されるのを避けるためにワイルドカードを引用符で囲み、次にループ内で引用符なしの変数を使用する (これは他のほとんどの場合ではやってはいけないことです) というトリックに注意してください。

答え3

-type fその偽の結果を避けるために、DopeGhoti の回答に追加する価値があります.

find . -maxdepth 1 -exec basename "{}" \; | cut -d'-' -f1 | sort -u
.
4855
5355
5855
find . -maxdepth 1 -type f -exec basename "{}" \; | cut -d'-' -f1 | sort -u
4855
5355
5855
$

元の試みと似たものを維持したい場合は、これを使用できます (lsただし、解析されるため、これは良くありません)。

ls -1 | grep ^....-  | cut -c1-4 | sort --unique

awk ベースのソリューション、依然として ls を解析中

ls -1 | awk -F- '{print $1}' | sort --unique

出力はすでにソートされているため、これらの各ケースでソートする必要はなくls、 を使用できますuniq

ls -1 | awk -F- '{print $1}' | uniq

sed ベースのソリューション

ls -1 | sed 's/-.*//' | uniq

ls の解析を回避する find / sed ソリューション

find . -type f -printf "%f\n" | sed 's/-.*//g' | sort --unique

「-」の前に常に4桁の数字が続く場合は、これは非常にエレガントです

find . -type f -printf "%.4f\n" | sort -u

答え4

zsh

myfiles=(*-*(.))
print -rl -- ${(u)myfiles[@]%%-*}

これは、配列に少なくとも1つのダッシュを含むすべての通常のファイル名を保存します。次に、配列の各要素に対してパラメータ展開を使用して、最初のダッシュとそれに続くすべてのものを削除します。重複する要素はフラグによって削除されます(u)
隠しファイルも選択するには、myfiles=(*-*(.D))

関連情報