名前に基づいてファイルを見つけて移動し、同時に名前を変更します。

名前に基づいてファイルを見つけて移動し、同時に名前を変更します。

年に基づいて名前が付けられたディレクトリがあり、テーマコードに基づくPDFファイルが含まれているとします。

ls出力は次のとおりです

$ ls -l
total 32
drwxrwxrwx 1 root root 4096 Apr  8 08:52 May-June-2011
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Nov-Dec-2011
drwxrwxrwx 1 root root 4096 Apr  8 20:36 Summer-2012
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Summer-2013
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Summer-2014
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Winter-2012
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Winter-2013
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Winter-2014

各ディレクトリには、タイトルコードに従ってpdfファイルが含まれています。

ls -l May-June-2011/
total 808
-rwxrwxrwx 1 root root 104193 May  1  2011 161901.pdf
-rwxrwxrwx 1 root root 103380 May  1  2011 161902.pdf
-rwxrwxrwx 1 root root 115664 May  1  2011 161903.pdf
-rwxrwxrwx 1 root root  88953 May  1  2011 161904.pdf
-rwxrwxrwx 1 root root 179268 May  1  2011 161905.pdf
-rwxrwxrwx 1 root root 116158 May 24  2011 161906.pdf
-rwxrwxrwx 1 root root 106033 May  1  2011 161907.pdf

つまり、すべてのディレクトリに16190{1..7}.pdf


161901.pdfここで、上記のすべてのディレクトリのすべてのエントリを特定のディレクトリ(たとえばxyz)に移動し、名前を親フォルダのname.pdfに変更したいとします。

説明する:-

以下はそのリストです161901.pdf

$ find -name 161901.pdf
./May-June-2011/161901.pdf
./Nov-Dec-2011/161901.pdf
./Summer-2012/161901.pdf
./Summer-2013/161901.pdf
./Summer-2014/161901.pdf
./Winter-2012/161901.pdf
./Winter-2013/161901.pdf
./Winter-2014/161901.pdf

./May-June-2011/161901.pdf新しい名前(ファイルが置かれているディレクトリ名)に移動されたらと思います。つまり、次へxyzMay-June-2011.pdf./May-June-2011/161901.pdf./xyz/May-June-2011.pdf

同様に、./Nov-Dec-2011/161901.pdftoなど(toまで)。./xyz/Nov-Dec-2011.pdf./Summer-2012/161901.pdf./xyz/Summer-2012.pdf./Winter-2014/161901.pdf./xyz/Winter-2014.pdf

予想される出力ls xyzは次のとおりです。

$ls xyz
May-June-2011.pdf
Nov-Dec-2011.pdf
Summer-2012.pdf
Summer-2013.pdf
Summer-2014.pdf
Winter-2012.pdf
Winter-2013.pdf
Winter-2014.pdf

どうすればいいですか? (ループやその他の方法find -execまたは使用方法)

答え1

PerlモジュールUnicode::戦い次の非常に便利なスクリプトが付属しています。名前を変更する(この名前はLinuxの標準と矛盾するので、これは不幸なことですrename(1)。)それであなたは次のことをすることができます:

mkdir xyz
find . -name '*.pdf' -print0 | \
    rename -0 's!^\.!xyz!;  s!/[^/]*\.pdf$!.pdf!'

Perlがなくても、いくつかのシェルパイピングを使用して同じことを実行できます。

mkdir xyz
find . -name '*.pdf' | sed 's/^/mv /' >src
find . -name '*.pdf' | sed 's!^\./!xyz/!; s!/[^/]*\.pdf$!.pdf!' >dest
join src dest | sh -
rm -f src dest

そして、他の人がすぐに指摘すると確信していますが、<(...)プロセス置換を使用して一行に入れることもできます。しかし、これが状況をより明確にするかどうかはわかりません。今日のコンピュータは、より詳細な構文を使用できるほど強力です。 ;)

答え2

findディレクトリツリーを再帰的に移動する必要がない場合は、ほとんど役に立ちません。ここでは単純なループとシェルワイルドカードで十分です。

for x in */161901.pdf; do
  mv -- "$x" "xyz/${x%/*}.pdf"
done

renameprenameまたは、Debian、Ubuntu、およびその派生製品(他のディストリビューションのLinuxコマンドではなくArchの場合rename)でPerlベースのコマンドを使用します。

rename 's!/.*!!; $_="xyz/$_.pdf"' */161901.pdf

またはzshを使用してください。

autoload -U zmv
zmv '(*)/161901.pdf' 'xyz/$1.pdf'

答え3

find -print1つの方法は、ファイルのリストを取得し、次のコマンドのawkように必要に応じて変換できる場所にパイプすることです。cp

$ find -name 161901.pdf -print | awk -v TARGET=xyz -F'/' '{ printf "cp %s %s/%s.pdf\n", $0, TARGET, $2; }'
cp ./May-June-2011/161901.pdf xyz/May-June-2011.pdf
cp ./Nov-Dec-2011/161901.pdf xyz/Nov-Dec-2011.pdf

その後、実行のためにシェルにパイプすることができます。

find -name 161901.pdf -print | awk -v TARGET=xyz -F'/' '{ printf "cp %s %s/%s.pdf\n", $0, TARGET, $2; }' | sh 

答え4

お持ちの場合名前の変更/名前の変更注文する

find -name 161901.pdf -exec prename -n 's!/!-!g; s!\W*!xyz/!' {} +

-nご覧になり、気に入ったら削除してください。

(Larry WallとRobin Barkerの名前はperl.debパッケージと共にインストールされ、Brian d FoyのUnicode::Tussle名前変更も可能です。)

関連情報