実行時にディレクトリを調べ、すべてのファイルを検索し、自動的にファイル名パターンを検索し、以下に説明する追加のロジックに従って移動するスクリプトを作成しています。
私のフォルダに次のファイルがあるとしましょう。
- AAA.txt
- 一時-203981.log
- 一時-098723.log
- 一時-123197.log
- 一時-734692.log
- test1.sh
- test2.sh
- test3.sh
スクリプトは自動的にディレクトリを検索し、名前に一致するプレフィックスを持つ4つのファイル(temp-XXX.log)と3つのファイル(testXXX.sh)を見つける必要があります。その後、ファイル数を見つけたら、それを定義された制限(例:3)と比較する必要があります。
指定された名前と一致するファイルの数が制限より大きい場合、見つかったファイルは一致するファイル名の部分として名前付きフォルダに移動する必要があります。
したがって、上記の親フォルダは次のようになります。
- AAA.txt
- temp.log(temp-734692.log、temp-123197.log、temp-098723.log、temp-203981.logを含むフォルダ)
- test.sh(test1.sh、test2.sh、test3.sh を含むフォルダーになります)
これが意味があることを願っています。
PS私はこのスクリプトでASHを使用しているので、素晴らしいbash機能なしで実行できるはずです。そうでなければ、これは簡単です。
ありがとうございます!
編集:始めるとすぐに明確さが変わりました。また、すべてのファイル名に事前定義された区切り記号(「&」など)を指定すると、簡単になります。スクリプトでは、区切り文字の前にあるファイル名に基づいて可変フォルダ名を生成する必要がありますが、これは作業がより明確で簡単になると思います。
答え1
動作していることを確認し、どのように動作するかを説明します。でテストしましたdash
。
メモ:ファイル名にはスペースや改行を含めないでください。
#!/bin/dash
limit=1
printf "%s\n" * |
sed 's/[-0-9]*\..*$//' |
uniq -c |
awk -v lim=${limit} '$1 >= lim {print $2}' |
sort -r |
while read -r i; do
for j in "${i}"*; do
[ -f "$j" ] || continue
dir=${i}.${j#*.}
[ -d "$dir" ] || mkdir "$dir"
mv -v "$j" "$dir"
done
done
ここに問題があります。たとえば、ファイル名が将来のディレクトリ名と同じ場合ですaaa.txt
。このaaa.txt
場合、ファイル名に余分な文字がないため、何も削除されないため、新しいディレクトリ名が同じであるため、エラーが発生します。
mkdir: cannot create directory ‘aaa.txt’: File exists
mv: 'aaa.txt' and 'aaa.txt' are the same file
この問題に対する解決策の1つは、想定されているディレクトリ名がファイル名と同じであることを確認してから、将来のディレクトリ名にいくつかの番号を追加することaaa1.txt
です。
デモ
スクリプトが実行される前に。
$ tree
.
├── aaa.txt
├── temp-098723.log
├── temp-123197.log
├── temp-203981.log
├── temp-734692.log
├── temp-new-file123.log
├── temp-new-file-2323-12.log
├── temp-new-file-342.log
├── test1.sh
├── test2.sh
└── test3.sh
0 directories, 11 files
スクリプトが実行された後: script.sh
$ tree
.
├── aaa.txt
├── temp.log
│ ├── temp-098723.log
│ ├── temp-123197.log
│ ├── temp-203981.log
│ └── temp-734692.log
├── temp-new-file.log
│ ├── temp-new-file123.log
│ ├── temp-new-file-2323-12.log
│ └── temp-new-file-342.log
└── test.sh
├── test1.sh
├── test2.sh
└── test3.sh
3 directories, 11 files
答え2
ここで質問した内容を誤解したかもしれませんが、私が言ったように、問題には比較的複雑な解決策が必要な微妙さがいくつかあると思います。つまり、目的のタスクを実行するためにスクリプトがどれほど簡単かわかりません。 。たとえば、サンプルファイルのリストを詳しく見てみましょう。
AAA.txt 一時-203981.log 一時-098723.log 一時-123197.log 一時-734692.log test1.sh test2.sh test3.sh
あなたの質問によると、このリストから抽出したいプレフィックスtemp
はとですtest
。これは、プレフィックスaaa
としてファイルが1つだけであり、しきい値の例が3であるため除外されます。ところで始まるファイルが7つあるのに、aaa
なぜ接頭辞がないのでしょうか?または、最初にファイル名のサフィックスに基づいてファイルをグループ化したいと思いますが、なぜ新しいサブディレクトリの1つではないのですか?このディスカッションは、プログラムがプレフィックスリストを引数として使用するのではなく、独自の潜在的なプレフィックスを決定したい場合は、問題の説明に解決する必要があるいくつかのあいまいさがあることを明らかにすることを願っています。作らなければならないのです)。te
te
t.log
temp-.log
temp.log
これは単純なものを使用するPythonスクリプトです。テリーツリーいくつかの制約を満たす最も長い一致プレフィックスを取得するために使用されるデータ構造(引数として提供できます):
#!/usr/bin/env python2
# -*- coding: ascii -*-
"""
trieganize.py
Use the trie data structure to look for prefixes of filenames in a given
directory and then reorganiz those files into subdirectories based on
those prefixes.
In this script the trie data structure is just a dictionary of the
following form:
trie = {
"count": integer,
"children": dictionary,
"leaf": boolean
}
Where the dictionary keys have the following semantics.
count:
stores the number of total descendents of the given trie node
children:
stores the child trie nodes of the given node
leaf:
denotes whether this trie corresponds to the final character in a word
"""
import sys
import os
import string
def add_word_to_trie(trie, word):
"""Add a new word to the trie."""
if word:
trie["count"] += 1
if word[0] not in trie["children"]:
trie["children"][word[0]] = \
{"count": 0, "children": {}, "leaf": False}
add_word_to_trie(trie=trie["children"][word[0]], word=word[1:])
else:
trie["leaf"] = True
return(trie)
def expand_trie(trie, prefix='', words=None):
"""Given a trie, return the list of words it encodes."""
if words is None:
words = list()
if trie["leaf"]:
words.append(prefix)
for character, child in trie["children"].iteritems():
if trie["children"]:
expand_trie(trie=child, prefix=prefix+character, words=words)
return(words)
def extract_groups_from_trie(
trie, threshold=0, prefix='', groups=None,
minimum_prefix_length=0,
maximum_prefix_length=float("inf"),
prefix_charset=string.ascii_letters,
):
"""Given a trie and some prefix constraints, return a dictionary which
groups together the words in the trie based on shared prefixes which
satisfy the specified constraints.
"""
if groups is None:
groups = dict()
if trie["count"] >= threshold:
children = {
character: child
for character, child in trie["children"].iteritems()
if (
child["count"] >= threshold and
len(prefix) + 1 >= minimum_prefix_length and
len(prefix) + 1 <= maximum_prefix_length and
character in prefix_charset
)
}
if not children:
groups[prefix] = expand_trie(trie, prefix)
else:
for character, child in children.iteritems():
extract_groups_from_trie(
trie=child, threshold=threshold,
prefix=prefix+character, groups=groups
)
return(groups)
def reorganize_files(basedir, suffix_separator='.', threshold=3):
"""Takes a path to a directory and reorganizes the files in that
directory into subdirectories based on the prefixes of their
filenames."""
# Get the list of file names
filenames = os.listdir(basedir)
# Group the filenames by suffix
suffixes = {}
for filename in filenames:
basename, separator, suffix = filename.rpartition(suffix_separator)
if suffix not in suffixes:
suffixes[suffix] = []
suffixes[suffix].append(basename)
# For each suffix, search for prefixes
for suffix, basenames in suffixes.iteritems():
# Initialize a trie object
trie = {"count":0, "children": {}, "leaf": False}
# Add the filenames to the trie
for basename in basenames:
add_word_to_trie(trie, basename)
# Break the filenames up into groups based on their prefixes
groups = extract_groups_from_trie(trie, threshold)
# Organize the groups of files into subdirectories
for prefix, group in groups.iteritems():
targetdir = os.path.join(basedir, prefix + suffix_separator + suffix)
os.mkdir(targetdir)
for basename in group:
filename = basename + suffix_separator + suffix
sourcefile = os.path.join(basedir, filename)
targetfile = os.path.join(targetdir, filename)
os.rename(sourcefile, targetfile)
if __name__=="__main__":
reorganize_files(basedir=sys.argv[1])
このPythonスクリプトをデモンストレーションするためにテストディレクトリを作成して埋める小さなシェルスクリプトを作成しました。
#!/usr/bin/bash
# create-test-dir.sh
rm -rf /tmp/testdir
mkdir -p /tmp/testdir
files=(
aaa.txt
temp-203981.log
temp-098723.log
temp-123197.log
temp-734692.log
test1.sh
test2.sh
test3.sh
)
for file in ${files[@]}; do touch "/tmp/testdir/${file}"; done
スクリプトを実行できます。
bash create-test-dir.sh
その後、テストディレクトリは次のようになります(実行中tree /tmp/testdir
)。
/tmp/テストディレクトリ/ |-- aaa.txt |-- 一時-098723.log |-- 一時-123197.log |-- 一時-203981.log |-- 一時-734692.log |-- test1.sh |-- test2.sh `--test3.sh ディレクトリ0個、ファイル8個
これでPythonスクリプトを実行できます。
python trieganize.py /tmp/testdir
その後、ファイルは次のように構成されます。
/tmp/テストディレクトリ/ |-- aaa.txt |--温度記録 |-- 一時-098723.log |-- 一時-123197.log |-- 一時-203981.log `--temp-734692.log `--test.sh |-- test1.sh |-- test2.sh `--test3.sh 2つのディレクトリ、8つのファイル
答え3
はい、bash
これにより作業が簡単になりますが、POSIXソリューションは次のようになります。
#!/bin/sh
for pattern in "$@"; do
set -- "$pattern"*
if [ $# -gt 2 ]; then
for f in "$@"; do
[ -f "$f" ] || continue
ext="${f##*.}"
dest="${pattern}.${ext}"
[ -d "$dest" ] || mkdir "$dest"
mv "$f" "$dest"
done
fi
done
exit
これにはさまざまなパターンが必要です(例:)./script temp test
。各パターンに対して、位置パラメータをパターンに一致するファイルに設定し、指定されたフォルダに移動します(パターンに<pattern>.<file_extension>
一致するファイルが3つ以上の場合)。あなたのサンプルファイルを使って期待した結果を得ました。
編集:$f
ディレクトリの移動などを避けるために、これを通常のファイルでテストしました。