Bagaimana saya bisa menggunakan wildcard ms-dos style dengan ls dan mv?

9

Saya mengalami musibah datang dari latar belakang MS-DOS - tetapi setidaknya itu membuat saya menghargai betapa jauh lebih kuatnya Linux. Saya telah berusaha untuk mendapatkan Linux-Fu secara normal, tetapi ada beberapa hal yang dapat dilakukan dengan DOS yang saya tidak yakin bagaimana melakukannya dengan paling mudah dengan Linux:

Mengganti Nama Banyak File - Menggunakan Dua Wildcard

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

Saya tahu saya bisa menggunakan di find -execsini tetapi apakah mungkin untuk menggunakan sintaks yang lebih pendek - mungkin mvdengan beberapa flag khusus atau sintaks? Saya kira kunci untuk ini adalah wildcard kedua * karena linux seharusnya tidak memiliki masalah dengan yang pertama (yaitu saya tahu cara memilih file yang ingin saya ganti namanya menggunakan wildcard)

Mengganti Nama File Tunggal - Menggunakan Satu Wildcard

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

Ini akan sangat membantu ketika mengganti nama nama file yang panjang dan sulit. Saya pikir mungkin saya bisa menggunakan mv file1.txt $1.bakuntuk berakhir dengan file1.txt.bakyang juga dapat diterima tetapi saya tidak yakin Anda dapat referensi $1inline parameter dengan perintah shell. Sekali lagi dalam kasus khusus ini hanya nyaman bagaimana ms-dos memastar *wildcard untuk digunakan sebagai semacam pencocokan penangkapan / penggantian untuk bagian dari nama file.

Memfilter Daftar Direktori dengan Wildcard

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) 

Saya tidak yakin apa sintaks yang tepat untuk melakukan itu ls, atau apakah itu mungkin. Jika saya melakukan sesuatu seperti ls t*itu akan muncul kembali ke direktori dimulai dengan t. Solusi saya telah menggunakan find . --max-depth 1 -iname "t*"atau sesuatu seperti ls -al | grep t- tidak ada yang sesingkat dan sesederhana dir t*itu.

Akhirnya, saya tahu saya dapat mengatur alias untuk membuat perintah-perintah panjang ini lebih pendek, tetapi saya ingin mempelajari beberapa linux-fu out-of-the-box untuk melakukan hal-hal ini karena kadang-kadang Anda terhubung ke sistem jarak jauh atau bekerja pada mesin baru.

Jadi bagaimana saya bisa mvdan lsfile dengan cara yang sama seperti yang saya gunakan dirdan renamefile?

cwd
sumber

Jawaban:

15

Salah satu perbedaan mendasar antara cmdshell Windows dan POSIX adalah siapa yang bertanggung jawab atas ekspansi wildcard. Shells melakukan semua ekspansi yang diperlukan sebelum memulai perintah sebenarnya yang Anda minta. cmd sebagian besar meneruskan pola wildcard ke perintah yang tidak dimodifikasi. (Saya katakan sebagian besar, karena saya pikir ada pengecualian, dan variabel lingkungan diperluas dalam sebagian besar keadaan.) Ini membuat penulisan renameyang akan bekerja dengan sintaks yang sama seperti dalam cmdcukup rumit.

Tetapi ada renameuntuk Linux - dengan argumen yang sangat berbeda, lihat halaman manual (yang agak singkat pada sistem saya, dan renameberasal dari util-linuxpaket pada sistem saya, yang seharusnya tersedia secara luas). Ganti nama pertama Anda akan dilakukan seperti ini:

rename .txt .bak *.txt

Perhatikan bahwa shell melakukan *ekspansi, jadi renameitu sendiri sebenarnya berpikir itu dipanggil seperti ini:

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

Jadi Anda bisa menebak versi file tunggal:

rename .txt .bak file1.txt

Jika Anda tidak ingin menggunakan renametetapi mengimplementasikannya sendiri, Anda bisa membuat fungsi untuk itu. Dengan asumsi Anda hanya ingin mengubah ekstensi file, dan untuk mengganti nama file tunggal, lihat ini:

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

$newfiledibangun menggunakan penghapusan substring untuk menghapus ekstensi asli, lalu menyatukan ekstensi baru. Anda dapat memperluas fungsi itu untuk menangani banyak file dengan relatif mudah.


Sedangkan untuk lspertanyaan Anda , gunakan -dsakelar. Ini akan mencegah lsdari daftar isi direktori.

Demo:

$ 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

Ganti nama wildcard

$ 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

Ganti nama file tunggal

$ 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

Default 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 itu tidak memeriksa direktori

$ 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
Tikar
sumber
sangat bagus! Saya pikir saya baru saja pindah sabuk dengan linux-fu saya! Terima kasih!
cwd
Kiat untuk sedikit maju dengan ini (dan menghindari jebakan): gunakan fungsi atau skrip sederhana untuk melihat apa yang terjadi ketika Anda melakukannya somefunc *.Extjika pola itu tidak cocok dengan file apa pun, dan mainkan dengan mengutip untuk melihat apakah Anda berhasil meneruskan pola di sekitar ( tanpa harus diperluas) antar fungsi. Tip keamanan: jangan digunakan di rmmana pun saat bereksperimen dengan ekspansi globbing / shell :-)
Mat
4

Satu hal yang perlu diingat ketika datang ke wildcard adalah bahwa mereka diperluas oleh shell. Aplikasi tidak tahu apakah Anda menggunakan wildcard atau mengetikkan nama. Misalnya, jika Anda mengetik rename *.txt *.bak, maka renameperintah melihat sesuatu seperti rename file1.txt file2.txt existingfile.bak. Tidak cukup informasi untuk melanjutkan.

Saya akan menangani pertanyaan tentang lspertama, karena lebih sederhana. Jika semua yang Anda inginkan adalah nama yang cocok, maka Anda tidak perlu ls, karena shell sudah melakukan ekspansi.

echo t*

Jika Anda ingin informasi lebih lanjut tentang file, maka lewat -dopsi ke ls, untuk mengatakannya untuk tidak mencantumkan isi direktori.

ls -ld t*

Tidak ada utilitas standar untuk mengganti nama file, karena sistem unix pertama tidak datang dengan satu. Metode portabel untuk mengubah nama file menggunakan loop dan sedikit verbose:

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

Ada beberapa utilitas umum untuk mengubah nama file, tidak ada yang dijamin untuk diinstal pada sistem unix yang diberikan, tetapi semuanya mudah untuk diinstal. Inilah yang utama:

  • renamedari util-linuxsuite, tersedia di setiap sistem Linux yang tidak tertanam (dan tempat lain). Pada Debian dan turunannya (termasuk Ubuntu), perintah ini disebut rename.ul. Asalkan tidak ada kejadian .txtselain ekstensi akhir, Anda dapat menulis

    rename .txt .bak *.txt
    
  • renameadalah skrip Perl yang dikirimkan oleh Debian dan turunannya /usr/bin/rename. Anda dapat mengganti nama file sesuai dengan perintah Perl sewenang-wenang.

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmv, yang dapat mengubah nama, menyalin, dan menautkan file sesuai dengan beberapa pola berbasis nama dan memiliki banyak opsi yang berkaitan dengan apa yang terjadi jika nama target sudah ada. Perhatikan bahwa Anda harus menggunakan tanda kutip untuk melindungi wildcard dari ekspansi oleh shell.

    mmv '*.txt' '#1.txt'
    
  • zmvadalah fungsi zsh , tersedia jika dan hanya jika shell Anda adalah zsh. Itu bisa cocok dengan pola zsh sewenang-wenang (sehingga Anda dapat mencocokkan nama file sesuai dengan ekspresi reguler sewenang-wenang, bukan hanya wildcard, dan Anda dapat mencocokkan file dengan kriteria lain seperti tanggal dan ukuran). zmvjuga dapat menyalin dan menautkan.

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

Jika Anda memiliki kontrol atas mesin yang Anda gunakan, rekomendasi saya adalah menggunakan zsh sebagai shell Anda (memiliki manfaat lain daripada bash) dan letakkan baris ini di ~/.zshrc:

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

noglobadalah fitur zsh yang memberi tahu shell untuk tidak memperluas wildcard dalam argumen perintah. Dengan cara ini Anda dapat menulis zmv *.txt \$1.txt(Anda harus selalu melindungi $dalam teks pengganti).

Gilles 'SANGAT berhenti menjadi jahat'
sumber