Apakah ada perintah linux seperti mv tetapi dengan regex?

41

Misalnya saya mau mv (.*?).sql $1.php,

apakah ada perintah yang memungkinkan saya menentukan pola pengubahan nama?

JoshRibs
sumber

Jawaban:

32

Seperti yang disebutkan orang lain, renamepandai dalam hal ini, tetapi bacalah halaman manual ( man rename) sebelum Anda mencobanya. Setidaknya ada dua alat yang sama sekali berbeda di luar sana yang disebut renamedan mana yang Anda miliki tergantung pada distribusi Anda. Menyebut mereka secara salah bisa berbahaya.

Inilah halaman manual untuk versi berbasis perl oleh Larry Wall yang dikirimkan bersama Ubuntu. Anda memberinya ekspresi perlrename 's/\.sql$/.php/' *.sql

Inilah halaman manual untuk penggantian nama yang dikirimkan dengan distribusi Red Hat dan CentOS yang lebih lama. Penggunaan adalah substitusi string sederhana sepertirename .sql .php *.sql

Anda juga bisa menggunakan bash one-liner untuk memproses setiap file satu per satu:

$ for f in *.sql; do mv -i "$f" "${f%%.*}.php"; done
Ryan Bright
sumber
Bisakah seseorang mengunggah biner Windows untuk ganti nama berbasis perl?
mcandre
Ganti nama versi Perl tidak dapat memindahkan file dari satu sistem file ke sistem file lainnya.
lilydjwg
bash one-liner sangat membantu, terutama ketika tidak memiliki renamefungsi (yaitu busybox)
artm
10

Ada rename(1), yang tidak menggunakan regex, tetapi bisa menyelesaikan masalah Anda:

rename .sql .php *.sql

Ada juga mmv(1), tapi saya tidak terbiasa dengan cara kerjanya.

Adam Rosenfield
sumber
Di Ubuntu dan Debian (tidak yakin tentang distribusi lain), /usr/bin/renametautan ke /usr/bin/prenamesecara default, yang membutuhkan regexps.
ℝaphink
5

Hari,

Anda juga bisa mencoba masuk

for i in $(\ls -d *.sql)
do
mv $i $(echo $i | sed -e 's/\.sql$/\.php/')
done

Atau untuk membuatnya gunakan regex, ubah sedikit ke

for i in $(\ls -d | egrep -e '.*\.sql')
do
mv $i $(echo $i | sed -e 's/\.sql$/\.php/')
done

untuk sedikit bersenang-senang coding shell. (-:

Rob Wells
sumber
2
Ini gagal dengan file yang berisi spasi putih di namanya, jadi berhati-hatilah. Seseorang seharusnya tidak mem-parsing lsoutput .
slhck
THe sedcontoh cukup baik, meskipun.
Bintang terang
2

Menjadi tukang ledeng, saya suka pipa :)

Catatan: jawaban ini verbose - sebagai pemula saya menghargainya ketika seseorang yang tahu meluangkan waktu untuk menjelaskan, jadi saya membayar 'maju'. Jika Anda bukan pemula, mohon panjang dan verbositas.

ls -1 *_201[67][0-9]* | sed -e 's/\(\(.\+\)[-_]\(201[67][0-9]\{4\}\)\([^.]\+\)\?\.[0-9a-z]\{2,3\}\)/mkdir -p \2\/\3; mv \1 \2\/\3\/\1/' | bash

Dimana:

ls -1 *_201[67][0-9]*

daftar semua file yang cocok dengan pola, dalam hal ini saya mencari file dengan tanggal dalam nama file dalam bentuk 'YYYYMMDD'

sed -e 's/\(\(.\+\)[-_]\(201[67][0-9]\{4\}\)\([^.]\+\)\?\.[0-9a-z]\{2,3\}\)/mkdir -p \2\/\3; mv \1 \2\/\3\/\1/'
#        : | |    |     |                  | |       |                    |:                                 :
#        : |^2....^    ^3..................^^4.......^                    |:                                 :
#        :^1..............................................................^:                                 :
#        /................filename.................pattern................./...mkdir...and....mv...command.../

^ 1: Grup tangkapan pertama - seluruh nama file

^ 2: Grup tangkapan ke-2 - bagian pertama dari pola nama file

^ 3: grup tangkapan ketiga - bagian nama file ke-2 - di sini, tanggal sebagai 'YYYYMMDD'

^ 4: grup tangkapan ke-4 - bagian nama file opsional antara tanggal dan ekstensi, dan ekstensi itu sendiri

Sooooo .... jika saya memiliki file bernama

CallLog_555123412_20161231-214403.7z

...kemudian

mkdir -p \2\/\3; mv \1 \2\/\3\/\1

sebenarnya berarti

# make directory and sub-directory
mkdir -p CallLog_555123412/20161231
# move file from current directory to sub-sub-directory just created
mv CallLog_555123412_20161231-214403.7z CallLog_555123412/20161231/CallLog_555123412_20161231-214403.7z

Perhatikan bahwa output dari perintah sed disalurkan melalui ke 'bash' untuk menjalankannya. Untuk melihat terlebih dahulu file yang diajukan bergerak TANPA benar-benar memindahkannya, hapus dulu '| bash 'di akhir, dan coba seperti ini:

ls -1 *_201[67][0-9]* | sed -e 's/\(\(.\+\)[-_]\(201[67][0-9]\{4\}\)\([^.]\+\)\?\.[0-9a-z]\{2,3\}\)/mkdir -p \2\/\3; mv \1 \2\/\3\/\1/'

Ini tidak akan membuat perubahan sama sekali, tetapi Anda akan melihat perintah yang akan dieksekusi JIKA Anda menjalankannya dengan '| bash 'ditandai pada akhirnya.

Ini berguna karena Anda dapat membuat sub-direktori yang Anda inginkan dari bagian-bagian dalam nama file, atau apa pun yang Anda tambahkan ke teks 'penggantian' dalam perintah sed. Perhatikan bahwa sed membutuhkan banyak karakter pelarian.

Kurung regex SED:

(...) membutuhkan pelolosan untuk ditangkap -> \ (... \)

{m, n} membutuhkan pelolosan untuk mengukur objek sebelumnya -> \ {m, n \}

/ mengharuskan melarikan diri dalam string pengganti -> \ /

[...] JANGAN mengharuskan melarikan diri untuk kelas karakter

\ 1 dalam string pengganti mengacu pada grup yang ditangkap pertama, dan seterusnya ...

PERINGATAN KEAMANAN: JANGAN PIPA APA PUN UNTUK 'bash' KECUALI JIKA ANDA SEPENUHNYA MEMAHAMI ...

Semoga itu bisa membantu membersihkan beberapa penyumbatan :)

skeetastax
sumber
1

Instal mmv, lalu lakukan ini:

mmv "*.sql" "#1.php"
Gepsens
sumber