Postępowanie z nazwami plików ze specjalnymi pierwszymi znakami (np. ♫)


30

Ostatnio natknąłem się na plik, którego nazwa zaczyna się od znaku „.”. Chciałem skopiować ten plik, załadować go ffmpegi odwołać się do niego na różne inne sposoby w terminalu. Zwykle automatycznie uzupełniam dziwne nazwy plików, ale to się nie udaje, ponieważ nie mogę nawet wpisać pierwszej litery.

Nie chcę przełączać się na mysz, aby wykonać manewr kopiuj-wklej. Nie chcę zapamiętywać wielu kodów dla możliwych scenariuszy. Moje rozwiązanie ad hoc polegało na zmianie vim, wklejeniu !lsi skopiowaniu danego znaku, a następnie wyjściu i wklejeniu go do terminala. To działało, ale jest dość przerażające.

Czy istnieje łatwiejszy sposób radzenia sobie z takimi scenariuszami?

UWAGA: Używam skorupy ryb, jeśli to zmienia rzeczy.


7
Czy możesz użyć innych części pliku do utworzenia wyrażenia regularnego do pracy z nim? *restoffile.avilub coś w tym stylu?
slm

1
W tym przypadku pozostała nazwa była mieszanką Kanji i Katakana (japoński skrypt), więc nie jest to łatwe.
ZirconCode

3
Zrozumiałem, pomyślałem, że zapytam. Czy odpowiedź jimmij go rozwiązuje? Czy miałbyś też ochotę wkleić zrzut ekranu z obrażających plików? Byłoby to prawdopodobnie pomocne dla innych, którzy mogą przeczytać to później.
slm

1
Próbuję go teraz uruchomić. Nie wiem, jak opublikować screeny, ale uruchomienie następujących poleceń da ci mój próbny problem:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode

1
Zsh możesz użyć opcji, aby zakładka dała ci menu, z którego możesz wybrać odpowiedni plik.
Kevin

Odpowiedzi:


35

Jeśli pierwszy znak nazwy pliku jest drukowalny, ale nie ma znaków alfanumerycznych ani białych znaków, możesz użyć [[:punct:]]operatora glob:

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

Hmm, nie wiedziałem o tych globalnych operatorach, przeczytałem o nich i nauczyłem się trochę (dziękuję), rozwiązuje to mój problem, który jest pojedynczym dziwnym plikiem w moim reż. Teraz mam ten problem z dużą ilością pliki, czy powinienem zadać nowe pytanie lub zaktualizować to?
ZirconCode,

Zaakceptowałem twoją odpowiedź, jutro opublikuję drugi scenariusz, kiedy będę miał czas. Dziękuję za pomoc.
ZirconCode

6

Najprostsze, jakie ls [^a-zA-Z0-9]*przychodzi mi do głowy, jest dla mnie skuteczne, ale odpowiedź Terdona lepiej jest zwrócić uwagę na opcję powłoki extglob lub nawet podejście niezależne od powłoki.


To dość przyzwoite dźgnięcie w to. Możesz zrobić ls [^[:alnum:]]*to samo. Ale lepiej jest użyć klasy postaci, jaką jest , niż klasy, której nie ma ; stąd ls [[:punct:]]*wyświetli ten plik.
Bogaty

6

ls ma kilka przełączników (takich jak - quote-name, --escape, --literal) do obsługi znaków niedrukowalnych, ale w tym przypadku wydaje się, że znak jest „drukowalny”, ale nie „wpisywalny” (przynajmniej na mojej klawiaturze! ), więc żaden z tych przełączników nie wydaje się pomóc.

Dlatego jako ogólne podejście „brutalnej siły”, aby pozbyć się plików z dowolnymi postaciami w ich nazwach, możesz to zrobić:

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

Znajdź wiersz zawierający niepoprawny plik. Całkiem prawdopodobne, że będzie to pierwsza linia, ale powiedzmy, że to piąta. Wydrukuj wiersz 5 i zakoduj go szesnastkowo:

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

Ignorując znak 0a (nowy wiersz), skonstruuj łańcuch zmiany znaczenia i użyj opcji -e echa, aby przetłumaczyć znaki zmiany znaczenia:

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

Teraz możesz skopiować / przenieść / usunąć w następujący sposób:

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

Ponadto, jeśli nie jesteś ograniczony do używania skryptu powłoki, możesz to zrobić w Pythonie w następujący sposób:

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

Korzystając z tego podejścia, możesz przetwarzać wiele plików, wystarczy napisać logikę wyboru właściwych plików i zmiany ich nazwy bez blokowania itp.

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

Podobnym podejściem byłoby wylistowanie wszystkich plików, które nie zaczynają się od „normalnych” znaków. W bash możesz to zrobić za pomocą

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

Nie wydaje się to jednak dostępne fish, więc możesz użyćfind zamiast tego :

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

4

Zmień nazwy dowiązań symbolicznych

Jednym z podejść do obsługi nazw plików ze znakami specjalnymi - jako pierwszych znaków lub w innym miejscu w nazwie pliku jest zmiana nazwy na prostszą .

Można tego użyć, nawet jeśli zachowane są oryginalne nazwy plików : Zmień nazwę kopii nazw plików.
Można to zrobić, kopiując pliki, ale także tworząc dowiązania symboliczne lub dowiązania twarde do plików i zmieniając ich nazwy. cptworzy dowiązania symboliczne zamiast kopii z opcją -s(-l dla twardych).

Użyj „detox”, aby wyczyścić nazwy

Do zmiany nazwy w celu wyczyszczenia nazw plików detoxmożna użyć; Zmienia nazwy plików, aby wyczyścić nazwy plików zgodnie z różnymi regułami zdefiniowanymi w detoxrcpliku. Domyślnie znaki UTF8 są właśnie usuwane; Z opcją -s utf_8-onlysą one zastępowane przez _:

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


„detox” na dowiązaniach symbolicznych

W połączeniu z pracą nad dowiązaniami symbolicznymi, jak opisano powyżej:

$ 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

Nie używam fish, ale dokumentacja mówi, że można wprowadzić znak Unicode, poprzedzając jego kod szesnastkowy znakiem \u(dla znaków 16-bitowych) lub \U(dla znaków 32-bitowych). Myślę, że kod dla jest 491eb, więc możesz zrobić:

mv \U000491ebabc.mp3 abc.mp3

zmienić nazwę ♫abc.mp3.

Zauważ, że potrzebujesz zer wiodących, w przeciwnym razie abcna końcu będą traktowane jako cyfry szesnastkowe i część kodu znaku; dla znaku 32-bitowego musisz wprowadzić 8 cyfr.


2

Nie wiem, czy było tak już w 2014 r., Kiedy zadałeś pytanie, ale w bieżących wersjach fish(od 2019 r.) Możesz nacisnąć Tabdwa razy, aby uzyskać wybór w stylu zsh, w którym możesz użyć klawiszy strzałek, aby wizualnie wybierz żądany plik bez konieczności wpisywania jakiejkolwiek części nazwy pliku.


2

Ryby nie obsługują symboli wieloznacznych ¹ z założenia.

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

Komenda nie szukać w ukrytych katalogów i wyświetla nazwy plików, które nie zaczynają się od znaków letters, digits, . _ -(cf dokumentacjifind ).

Uwaga: $argv jest specjalną zmienną tablicową (skorupa ryby), która zawiera argumenty funkcji, dlatego podstawowe polecenie może otrzymać dowolne wyrażenie (np. Alias ).

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

¹ W rzeczywistości Fish obsługuje rozwijanie nawiasów (rozszerzenie zmiennej tablicowej), ale Bash używa innej terminologii (rozszerzenia parametrów i nazw plików).



0

Nie powiedziałeś, czy chcesz zachować te problematyczne nazwy plików. Jednym z rozwiązań może być „rozwiązanie” problemu raz na zawsze poprzez zmianę nazwy (części lub wszystkich) plików na nazwy, które można wpisać, uruchamiając ten skrypt:

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

Spowoduje to wyświetlenie istniejących nazw plików, a po nich każdego ...?. Wystarczy wpisać, Enteraby pozostawić plik bez zmian; lub wpisz nową nazwę, aby zmienić nazwę. Ta -iopcja spowoduje wyświetlenie monitu o potwierdzenie zastąpienia, jeśli podasz nazwę innego istniejącego pliku.

Ten skrypt można zmodyfikować na kilka sposobów:

  • Możesz zmodyfikować symbol wieloznaczny ( *) na coś bardziej restrykcyjnego, np. *.avi *.movAbyś nie musiał patrzeć na każdy plik.
  • Możesz zmienić mvnacp , tak aby zachować kopię pliku z obecną nazwą i utworzyć (tymczasowe?) Kopiowanie z typeable nazwy.
  • Możesz utworzyć nową nazwę pliku na podstawie istniejącej nazwy pliku. Na przykład,

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

    co pozwala spoliczkować prefiks przed starą nazwą. Jeśli wybierzesz unikalny prefiks, pozwoli to na użycie autouzupełniania.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.