Menambahkan baris baru ke banyak file

1

Saya mencoba menambahkan baris baru ke banyak file dengan perintah berikut:

find -name *.ovpn -exec sh echo "line to append" >> {} \;

sebelum melakukan ini, saya menjalankan perintah yang berbeda untuk memastikan itu akan bekerja seperti yang saya harapkan:

find -name *.ovpn -exec sh echo "hello" \;

tetapi yang dilakukan hanyalah mencetak "sh: 0: Tidak dapat membuka gema" untuk setiap file yang ditemukan.

Andrew Davis
sumber

Jawaban:

4

Ada beberapa masalah.

>>dalam perintah pertama Anda akan ditafsirkan oleh shell Anda saat ini sebagai pengalihan ke file yang benar-benar bernama {}, kecuali itu dikutip.

*.ovpndapat diperluas dengan shell globbing sebelum finddijalankan. Ini akan terjadi jika Anda memiliki setidaknya satu objek di direktori saat ini yang cocok dengan pola. Anda ingin mengutip ini. Bandingkan pertanyaan ini .

Anda mendapatkan Can't open echokarena memang Anda mengatakan shuntuk membuka echo. Untuk menjalankan perintah yang Anda butuhkan sh -c.

findtanpa menentukan jalurnya tidak portabel (bandingkan pertanyaan ini ). Meskipun Anda bisa lolos dengan ini, saya menyebutkan masalah ini untuk membuat jawaban lebih bermanfaat bagi pengguna lain.

Ini adalah versi peningkatan dari perintah pertama Anda yang agak berfungsi (jangan jalankan, terus membaca):

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "{}"' \;

Perhatikan saya harus menggandakan penawaran {}di dalam kutipan tunggal. Kutipan ganda ini "dilihat" oleh shdan membuat nama file dengan spasi dll berfungsi sebagai target pengalihan. Tanpa penawaran Anda mungkin berakhir dengan echo "line to append" >> foo bar.ovpnyang setara dengan echo "line to append" bar.ovpn >> foo. Mengutip membuatnya sebagai echo "line to append" >> "foo bar.ovpn"gantinya.

Sayangnya nama file yang mengandung "akan memecah sintaks ini.

Cara yang tepat untuk lulus {}untuk shtidak untuk memasukkannya ke dalam perintah string tetapi untuk lulus isinya sebagai argumen yang terpisah:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$0"' {} \;

$0di dalam string perintah meluas ke argumen pertama yang kita shdapatkan -c '…'. Sekarang bahkan "dalam nama file tidak akan merusak sintaks.

Biasanya (seperti dalam naskah) untuk merujuk pada argumen pertama yang Anda gunakan $1. Inilah alasan beberapa pengguna lebih suka menggunakan argumen dummy $0, seperti ini:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' dummy {} \;

Jika itu skrip, $0akan diperluas ke namanya. Itu sebabnya tidak jarang melihat ini dummybenar-benar menjadi sh(atau bash, jika seseorang memanggil bash -c …dll):

find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' sh {} \;

Tapi tunggu! findpanggilan terpisah shuntuk setiap file tunggal. Saya tidak berharap Anda memiliki ribuan .ovpnfile, tetapi secara umum Anda mungkin ingin memproses banyak file tanpa memunculkan proses yang tidak perlu. Kami dapat mengoptimalkan pendekatan dengan tee -ayang dapat menulis ke banyak file sebagai satu proses:

find . -name '*.ovpn' -exec sh -c 'echo "line to append" | tee -a "$@" >/dev/null' sh {} +

Perhatikan {} +, ini melewati beberapa jalur sekaligus. Di dalam perintah dieksekusi oleh sh -ckita mengambil mereka dengan "$@", yang mengembang ke "$1" "$2" "$3" …. Dalam hal ini argumen dummy yang terisi (tidak digunakan) $0adalah suatu keharusan.

Secara umum ada juga masalah ini: Mengapa printflebih baik daripada echo? Namun dalam hal ini Anda menggunakan echotanpa opsi dan string yang didapat bersifat statis, jadi seharusnya tidak masalah.

Kamil Maciorowski
sumber