Mengapa perintah xargs ini tidak berfungsi?

14

Saya ingin menghapus semua ekstensi .sh jadi ini:

ls *.sh | xargs -I {} mv {} `basename {} .sh`

Namun tidak berfungsi, berperilaku seperti basenamemengembalikan nama file yang tidak berubah.

Mengapa berperilaku seperti itu?

Misalnya, ini berfungsi:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

EDIT :

Solusi: kutipan tunggal mencegah `basename ...`evaluasi oleh shell sebelum perintah dijalankan.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'
majkinetor
sumber

Jawaban:

12

Karena perintah basename dijalankan sebelum pipeline dijalankan. Untuk membuat ini berfungsi, Anda perlu xargs untuk mengeksekusi nama bas dan Anda dapat melakukannya dengan sh -c, misalnya:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

Catatan:

  • Jika Anda tidak tahu di xargsmana harus memasukkan nama file, mereka akan ditambahkan pada akhir baris perintah.
  • Anda harus menggunakan -L1sakelar atau padanannya, sehingga xargshanya meneruskan satu argumen sh.
  • Menggunakan output dari lsmungkin memiliki efek yang tidak diinginkan .

Edit

Opsi usang yang dihapus, terima kasih TechZilla

Thor
sumber
3
Poin pertama Anda salah, kecuali jika Anda maksudkan bahwa itu adalah default untuk setiap -iopsi, tetapi opsi 'klasik' tersebut telah usang. Sebagai contoh untuk menggunakan hanya satu opsi / baris, halaman manual POSIX baru merekomendasikan -L1. Untuk memanggil perilaku lama -i, halaman merekomendasikan -I'{}'opsi.
JM Becker
Jadi, ini sebenarnya tentang simbol "" bukan. Saya kira 'mencegah evaluasi shell ``. Lihat hasil edit saya.
majkinetor
@ TechZilla: terima kasih atas koreksi. @majkinetor: ya dan tidak, Anda perlu menunda evaluasi, tapi saya rasa Anda tidak bisa menggunakan backticks (`).
Thor
1
@majkinetor: ah, saya mengerti maksud Anda sekarang. Untuk mengubah nama file dengan cara ini saya lebih suka menggunakan rename, misalnya: rename 's/\.sh//' *.sh. Coba dulu dengan dry-run ( -n).
Thor
1
@majkinetor: renamebekerja dengan baik, dan cukup sederhana, tapi ingat itu sangat spesifik distribusi. Distribusi berbasis RHEL dan Debian menyediakan renameperintah yang berbeda , jadi orang harus mengingatnya saat membuat skrip lintas-distro.
JM Becker
4

Saya tidak yakin tentang pertanyaan Anda, apakah Anda benar-benar bertanya mengapa kalimat pertama Anda tidak berfungsi? Atau apakah Anda mencari metode yang tepat untuk mengganti nama semua file .sh?

Dengan asumsi itu adalah metode terbersih, saya lebih suka menyiapkan opsi perintah sebelumnya xargs . Untuk menghapus ekstensi file .sh, saya sering mempertimbangkan pendekatan ini,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
JM Becker
sumber