特別な最初の文字を含むファイル名の処理(例:♫)


30

最近、名前が文字「character」で始まるファイルに出会いました。このファイルをコピーしてに送りffmpeg、ターミナルで他のさまざまな方法で参照したかったのです。私は通常、奇妙なファイル名をオートコンプリートしますが、最初の文字を入力することさえできないため、これは失敗します。

コピーアンドペースト操作を実行するためにマウスに切り替えたくありません。考えられるシナリオのために、大量のコードを記憶したくありません。私のアドホックな解決策は、問題のキャラクターに切り替えvim、貼り付け!ls、コピーしてから、終了してターミナルに貼り付けることでした。これは機能しましたが、非常に恐ろしいです。

そのようなシナリオに対処する簡単な方法はありますか?

注:物事を変更する場合、私は魚の殻を使用しています。


7
ファイルの他の部分を使用して正規表現を作成し、それを使用できますか?*restoffile.aviまたはこのような何か?
slm

1
この場合、残りの名前は漢字とカタカナ(日本語のスクリプト)の混合であったため、簡単ではありませんでした。
ZirconCode 14年

3
理解した、私はちょうど尋ねると思った。jimmijの答えはそれを解決しますか?また、問題のあるファイルのスクリーンショットを貼り付けていただけますか?後でこれを読むかもしれない他の人に役立つでしょう。
slm

1
私は今それを機能させようとしています。私はscreenYのを投稿する方法を知りませんが、次のコマンドを実行すると、あなたに私のモック問題を与える:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode

1
zshを使用すると、オプションを使用して、適切なファイルを選択できるメニューをタブに表示できます。
ケビン14年

回答:


35

ファイル名の最初の文字が印刷可能で、英数字でも空白でもない場合、[[:punct:]]glob演算子を使用できます。

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt

うーん、これらのグロブ演算子について知らなかったので、それらを読んで少し学びました(ありがとう)、それは私のディレクトリにある単一の奇妙なファイルである問題を解決します。ファイル、新しい質問をするか、これを更新する必要がありますか?
ZirconCode 14年

あなたの答えを受け入れました。明日、時間があるときに2番目のシナリオを投稿します。お手伝いありがとう。
ZirconCode 14年

6

私に起こる最も簡単なことは、私にとってはls [^a-zA-Z0-9]*トリックです。しかし、terdonの答えは、extglobシェルオプションやシェルに依存しないアプローチに注意を向けるという点で優れています。


これで十分です。ls [^[:alnum:]]*同じことができます。しかし、そうではない文字クラスでなく、文字クラスを使用する方が良いです。したがって、このファイルがリストされます。ls [[:punct:]]*
リッチ

6

lsには、印刷できない文字を処理するためのいくつかのスイッチ(--quote-name、-escape、-literalなど)がありますが、この場合、文字は「印刷可能」ですが「タイプ可能」ではないようです(少なくとも私のキーボードでは! )、これらのスイッチはどれも役に立たないようです。

したがって、名前に任意の文字が含まれるファイルを削除する一般的な「ブルートフォース」アプローチとして、これを行うことができます。

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ♫
     2  f1.txt
     3  f2.txt

問題のあるファイルを含む行を見つけます。おそらく1行目ですが、5行目だとしましょう。5行目を印刷し、16進数でエンコードします。

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....

0a(改行)文字を無視し、エスケープ文字列を作成し、echoの-eオプションを使用してエスケープを変換します。

$ echo -e '\xe2\x99\xab'
♫

次のようにコピー/移動/削除できます:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘♫’ -> ‘better_name’

また、シェルスクリプトの使用に限定されていない場合は、次のようにPythonで実行できます。

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
♫
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')

このアプローチを使用すると、多くのファイルを処理できます。正しいファイルを選択し、上書きせずに名前を変更するためのロジックを記述するだけです。

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'

5

同様のアプローチは、「通常の」文字で始まらないすべてのファイルをリストすることです。bashでは、これを行うことができます

$ shopt -s extglob
$ ls !([[:alpha:]]*)

ただし、それはで利用できないようですfishので、find代わりに使用できます:

$ find . -type f -not -name '[[:alpha:]]*'

4

シンボリックリンクの名前を変更する

ファイル名の最初の文字または他の場所に特殊文字を含むファイル名を処理する1つの方法は、より単純な名前に名前変更することです。

これは、元のファイル名保持する必要がある場合でも使用できます。ファイル名のコピーの名前を変更します。
ファイルをコピーするだけでなく、ファイルへのシンボリックリンクまたはハードリンクを作成し、これらの名前を変更することでも実行できます。cpオプション-s-lハードリンク用)でコピーの代わりにシンボリックリンクを作成します。

「デトックス」を使用して名前を消去します

ファイル名を消去するために名前を変更するにdetoxは、使用できます。ファイルに定義されているさまざまなルールに従って、ファイル名をクリーンアップするためにファイル名を変更しますdetoxrc。デフォルトでは、UTF8文字は削除されます。オプション-s utf_8-onlyを使用すると、次のように置き換えられます_

$ touch '♫ 漢字カ' ♫foo
$ ls -1
♫foo
♫ 漢字カ
$ detox -s utf_8-only * 
$ ls -1                
_ ___
_foo


シンボリックリンクの「デトックス」

上記のようなシンボリックリンクでの作業と組み合わせて:

$ mkdir orig
$ cd orig 
$ touch '♫ 漢字カ' ♫foo
$ cd ..
$ mkdir clean
$ cd clean 
$ cp -s ../orig/* .
$ ll               
lrwxrwxrwx 1 14 Oct  8 05:52 ♫foo -> ../orig/♫foo
lrwxrwxrwx 1 21 Oct  8 05:52 ♫\ 漢字カ -> ../orig/♫\ 漢字カ
$ ls -1
♫foo
♫ 漢字カ
$ detox --special -s utf_8-only *
$ ll                                
lrwxrwxrwx 1 21 Oct  8 05:52 _\ ___ -> ../orig/♫\ 漢字カ
lrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/♫foo

2

を使用しませんfishが、ドキュメントでは、16進文字コードの前に\u(16ビット文字の場合)または\U(32ビット文字の場合)を付けることでUnicode文字を入力できると書かれています。のコード491ebであると思うので、次のことができます。

mv \U000491ebabc.mp3 abc.mp3

名前を変更し♫abc.mp3ます。

先行ゼロが必要であることに注意してください。そうabcでない場合、末尾は16進数として扱われ、文字コードの一部になります。32ビット文字の場合、8桁を入力する必要があります。


2

あなたが質問したときに2014年にすでにそうだったかどうかはわかりませんが、現在のバージョンfish(2019年)では、Tab2回押すと、矢印キーを使用してzshスタイルの選択を取得できますファイル名の一部を入力することなく、目的のファイルを視覚的に選択します。


2

Fishは、設計上、ブラケットワイルドカード ¹をサポートしていません。

function find_special_filename
    find ! -path './.*' -name '[^-.a-zA-Z0-9_]*' $argv
end

このコマンドは隠しディレクトリを検索せず、文字lettersdigitsで始まらないファイル名を表示します. _ -(のドキュメントをfind参照)。

注: $argvは、関数の引数を含む特別な配列変数(Fishシェル)であるため、基になるコマンドは任意の式(エイリアスなど)を受け取る場合があります。

find_special_filename -exec mv '{}' misc/ \;

¹ 実際、Fishはブラケット拡張(配列変数拡張)をサポートしていますが、Bashは別の用語(パラメーターとファイル名の拡張)を使用しています。



0

これらの問題のあるファイル名を保持するかどうかは言いませんでした。解決策の1つは、ファイル(一部またはすべて)の名前をこのスクリプトを実行して入力できる名前に変更することにより、問題を一度だけ「修正」することです。

#!/bin/sh
for old in *
do
      printf "%s ...? " "$old"
      if read new  &&  [ "$new" != "" ]
      then
             mv -i "$old" "$new"
      fi
done

これにより、既存のファイル名がリストされ、それぞれの後に...?Enterファイルをそのまま残すには、単に入力します。または、新しい名前を入力して名前を変更します。この-iオプションにより、別の既存ファイルの名前を指定した場合、上書きの確認を求められます。

このスクリプトは、いくつかの方法で変更できます。

  • ワイルドカード(*)をのようなより制限的なものに変更することができ*.avi *.movます。たとえば、すべてのファイルを見る必要はありません。
  • toを変更しmvcp、現在の名前でファイルのコピーを保持し、入力可能な名前で(一時的な?)コピーを作成できます。
  • 既存のファイル名に基づいた新しいファイル名を作成できます。例えば、

    if read pfx  &&  [ "$pfx" != "" ]
    then
            mv -i "$old" "$pfx$old"
    fi
    

    これにより、古い名前の前にプレフィックスを付けることができます。一意のプレフィックスを選択した場合、これによりオートコンプリートを使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.