Jak używać symboli wieloznacznych w stylu ms-dos z ls i mv?

9

Mam nieszczęście pochodzić ze środowiska MS-DOS - ale przynajmniej to sprawia, że ​​doceniam, jak potężniejszy jest Linux. Pracowałem nad tym, aby mój Linux-Fu osiągnął najwyższy poziom, ale jest kilka rzeczy, które można zrobić z DOS-em, ale nie jestem pewien, jak najłatwiej to zrobić z Linuksem:

Zmienianie nazw wielu plików - za pomocą dwóch symboli wieloznacznych

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\>rename *.txt *.bak

c:\> dir

Directory of c:\
    file1.bak
    file2.bak
    file3.bak
    file4.bak

Wiem, że mógłbym find -exectutaj użyć , ale można użyć krótszej składni - być może mvze specjalnymi flagami lub składnią? Wydaje mi się, że kluczem do tego jest drugi * symbol wieloznaczny, ponieważ linux nie powinien mieć problemu z pierwszym (tzn. Wiem, jak wybrać pliki, których nazwę chcę zmienić za pomocą symboli wieloznacznych)

Zmiana nazwy pojedynczego pliku - za pomocą jednego symbolu wieloznacznego

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

Byłoby to szczególnie pomocne przy zmianie nazwy długich i nieporęcznych nazw plików. Pomyślałem, że może przydałbym się mv file1.txt $1.bakdo tego, file1.txt.bakco też byłoby akceptowalne, ale nie jestem pewien, czy można odwołać się do $1parametru w linii za pomocą polecenia powłoki. Ponownie w tym konkretnym przypadku jest po prostu wygodne, jak ms-dos potępia *znak wieloznaczny, który ma być używany jako rodzaj dopasowania przechwytywania / zamiany dla części nazwy pliku.

Filtrowanie list katalogów za pomocą symboli wieloznacznych

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt
    text.txt
    \temp       (directory) 

c:\> dir file*

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\> t*

Directory of c:\
    text.txt
    \temp       (directory) 

Nie jestem pewien, jaka jest właściwa składnia do robienia tego ls, ani czy jest to w ogóle możliwe. Jeśli zrobię coś takiego, ls t*to od razu przejdzie do katalogów t. Moje obejście albo było używane, find . --max-depth 1 -iname "t*"albo coś w tym rodzaju ls -al | grep t- żadne z nich nie jest tak krótkie i proste, jak dir t*jest.

W końcu wiem, że mogę skonfigurować aliasy, aby skrócić te długie polecenia, ale chciałbym nauczyć się gotowego linux-fu do robienia tych rzeczy, ponieważ czasami jesteś podłączony do zdalnego systemu lub pracujesz na nowej maszynie.

Więc jak mogę mvi lspliki w taki sam sposób, jak kiedyś diri renamepliki?

cwd
źródło

Odpowiedzi:

15

Jedną z podstawowych różnic między cmdpowłokami Windows i POSIX jest to, kto jest odpowiedzialny za rozszerzenia symboli wieloznacznych. Powłoki wykonują wszystkie wymagane rozszerzenia przed uruchomieniem rzeczywistych poleceń, o które prosiłeś. cmd przeważnie przekazuje wzorce symboli wieloznacznych do niezmodyfikowanych poleceń. (Mówię głównie, ponieważ uważam, że są wyjątki, a zmienne środowiskowe są rozszerzane w większości przypadków.) To sprawia, że ​​pisanie takiego rename, które działałoby z taką samą składnią jak w cmddość trudnym.

Ale jest renameLinux - z zupełnie innymi argumentami, sprawdź stronę podręcznika (która jest trochę zwięzła w moim systemie i renamepochodzi z util-linuxpakietu w moim systemie, który powinien być powszechnie dostępny). Twoja pierwsza zmiana nazwy będzie następująca:

rename .txt .bak *.txt

Zauważ, że powłoka dokonuje *rozszerzenia, więc renamesama uważa, że ​​została wywołana w następujący sposób:

rename .txt .bak file1.txt file2.txt file3.txt ...

Możesz więc zgadnąć wersję z jednym plikiem:

rename .txt .bak file1.txt

Jeśli nie chcesz używać, renameale zaimplementuj to sam, możesz dla tego stworzyć funkcję. Zakładając, że chcesz tylko zmienić rozszerzenie pliku, a jeśli chcesz zmienić nazwę pojedynczego pliku, spójrz na to:

$ function chext() {
  newext="$1"
  file="$2"
  newfile="${file%.*}$newext"
  echo mv "$file" "$newfile"
}
$ chext .csv test.txt
mv text.txt text.csv

$newfilejest zbudowany przy użyciu usuwania podciągów w celu usunięcia oryginalnego rozszerzenia, a następnie konkatenuje nowe rozszerzenie. Możesz rozszerzyć tę funkcję, aby stosunkowo łatwo obsługiwać wiele plików.


Jeśli chodzi o twoje lspytanie, użyj -dprzełącznika. Zapobiegnie to lswyświetlaniu zawartości katalogów.

Próbny:

$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:29 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.csv
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Zmiana nazwy symbolu wieloznacznego

$ rename .csv .txt f*
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Zmiana nazwy jednego pliku

$ rename .txt .csv f1.txt 
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Domyślny ls

$ ls -l t*
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

test:
total 0
-rw-r--r-- 1 owner users 0 Jan  7 17:33 dont_show_me_please

ls który nie sprawdza katalogów

$ ls -ld t*
drwxr-xr-x 2 owner users 4096 Jan  7 17:33 test
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv
Mata
źródło
bardzo dobrze! myślę, że właśnie przesunąłem pasek z linux-fu! dzięki!
cwd
Wskazówka, aby trochę z tym postępować (i uniknąć pułapek): użyj prostych funkcji lub skryptów, aby zobaczyć, co się stanie, gdy zrobisz, somefunc *.Extjeśli ten wzorzec nie pasuje do żadnego pliku, i baw się cytowaniem, aby sprawdzić, czy uda ci się przekazać wzór ( bez rozszerzania) między funkcjami. Wskazówka bezpieczeństwa: nie używaj rmnigdzie podczas eksperymentowania z rozszerzaniem / rozszerzaniem powłoki :-)
Mat.
4

Jedną rzeczą, o której należy pamiętać, jeśli chodzi o symbole wieloznaczne, jest to, że są one rozszerzane przez powłokę. Aplikacja nie wie, czy użyłeś symboli wieloznacznych, czy wpisałeś nazwy. Na przykład, jeśli wpiszesz rename *.txt *.bak, renamepolecenie zobaczy coś w rodzaju rename file1.txt file2.txt existingfile.bak. To za mało informacji, aby kontynuować.

lsNajpierw zajmę się pytaniem , ponieważ jest prostsze. Jeśli wszystko, czego potrzebujesz, to pasujące nazwy, to nie potrzebujesz ls, ponieważ powłoka już dokonuje rozszerzenia.

echo t*

Jeśli chcesz uzyskać więcej informacji o plikach, przekaż -dopcję do ls, aby powiedzieć jej, aby nie wyświetlała zawartości katalogów.

ls -ld t*

Nie ma standardowego narzędzia do zmiany nazw plików, ponieważ pierwsze systemy uniksowe nie były dostarczane z jednym. Przenośna metoda zmiany nazw plików wykorzystuje pętlę i jest trochę szczegółowa:

for x in *.txt; do mv -- "$x" "${x%.txt}.bak"; done

Istnieje kilka popularnych narzędzi do zmiany nazw plików, z których żadne nie ma gwarancji zainstalowania w danym systemie uniksowym, ale wszystkie są łatwe do zainstalowania. Oto główne:

  • renamez util-linuxpakietu, dostępny w każdym niewbudowanym systemie Linux (i nigdzie indziej). W Debianie i pochodnych (w tym Ubuntu) to polecenie jest wywoływane rename.ul. Pod warunkiem, że nie wystąpi .txtinne niż końcowe rozszerzenie, możesz pisać

    rename .txt .bak *.txt
    
  • renamejest skryptem Perla, który dostarcza Debian i pochodne /usr/bin/rename. Możesz zmieniać nazwy plików według dowolnych poleceń Perla.

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmv, który może zmieniać nazwy, kopiować i łączyć pliki zgodnie z kilkoma wzorcami opartymi na nazwach i ma wiele opcji związanych z tym, co się stanie, jeśli nazwa docelowa już istnieje. Pamiętaj, że musisz używać cudzysłowów, aby chronić symbole wieloznaczne przed rozwinięciem przez powłokę.

    mmv '*.txt' '#1.txt'
    
  • zmvjest funkcją zsh , dostępną tylko wtedy, gdy twoją powłoką jest zsh. Może dopasowywać dowolne wzorce zsh (dzięki czemu można dopasowywać nazwy plików według dowolnych wyrażeń regularnych, nie tylko symboli wieloznacznych, i można dopasowywać pliki według innych kryteriów, takich jak daty i rozmiary). zmvmożna również skopiować i połączyć.

    zmv '(*).txt' '$1.txt'
    

Jeśli masz kontrolę nad używanymi maszynami, zalecam użycie zsh jako powłoki (ma to inne zalety niż bash) i umieszczenie tych linii w ~/.zshrc:

autoload -U zmv
alias zmv='noglob zmv -w'
alias zcp='zmv -C'
alias zln='zmv -L'
alias zsy='zmv -Ls'

noglobjest funkcją zsh, która mówi powłoce, aby nie rozwijała symboli wieloznacznych w argumencie polecenia. W ten sposób możesz pisać zmv *.txt \$1.txt(zawsze musisz zabezpieczyć $tekst zastępczy).

Gilles „SO- przestań być zły”
źródło