Bagaimana cara mengganti spasi di semua nama file dengan garis bawah di Linux menggunakan skrip shell?

17

Saya mencoba mengikuti skrip shell yang harus mengganti spasi dari semua nama file xml

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

Misalkan, saya punya file xml dengan nama xy z.xml, maka ia memberikan:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory
krishna
sumber

Jawaban:

28

Gunakan ini dengan bash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findakan mencari file dengan spasi di namanya. Nama file akan dicetak dengan nullbyte ( -print0) sebagai pembatas untuk mengatasi nama file khusus. Kemudian readbuiltin membaca nama file yang dibatasi oleh nullbyte dan akhirnya mvmengganti spasi dengan garis bawah.

EDIT: Jika Anda ingin menghapus spasi di direktori juga, ini sedikit lebih rumit. Direktori diubah namanya dan kemudian tidak lagi dapat diakses oleh namanya findditemukan. Coba ini:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

The sort -rzmembalikkan memesan berkas, sehingga file terdalam di folder adalah yang pertama untuk bergerak dan folder itu sendiri akan menjadi yang terakhir. Jadi, tidak pernah ada folder yang diganti namanya sebelum semua file dan folder diubah namanya di dalamnya. The mvperintah dalam loop adalah sedikit berubah juga. Dalam nama target, kami hanya menghapus spasi di nama file, jika tidak, file tersebut tidak dapat diakses.

kekacauan
sumber
Saya mencoba mengganti spasi dengan garis bawah di semua direktori tetapi memberikan kesalahan karena setelah mengubah nama direktori itu tidak dapat diakses.
krishna
@ Krishna Saya menambahkan suntingan ke jawaban saya.
kekacauan
1
@chaos wow, hanya menjalankan keduanya pada dua sistem dan itu bekerja seperti pesona, beberapa file dan dirs tidak melalui tetapi hanya beberapa
somethingSomething
Pada macOS kita perlu menentukan direktori dalam perintah find sebelum opsi -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter
17
  1. Menggunakan rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    atau dengan $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. Menggunakan mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    atau dengan $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;
AB
sumber
Saya tidak tahu mengapa tetapi perintah Anda yang diberikan tidak bekerja untuk saya. Itu tidak menunjukkan kesalahan dan output.
krishna
@krishna dikoreksi, maaf
AB
1
Ganti nama bekerja untuk saya. Fistbump!
Brian Piercy
1

Ini adalah metode yang saya temukan saat menghadapi masalah yang sama:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

Saya sedang menulis file skrip bash untuk secara otomatis memperbarui sertifikat ssl saya.

NekoMisaki
sumber
1

Gunakan rename:

rename 's/\s/_/g' ./*.xml

Tidak perlu find:)

Jan Werkhoven
sumber
1
tambahkan trailing g ke regex dan itu berfungsi dengan baik. 's / \ s / _ / g'
jbrahy
Tip yang bagus, terima kasih :)
Jan Werkhoven