Sementara saya telah menggunakan BASH selama beberapa tahun, pengalaman saya dengan skrip BASH relatif terbatas.
Kode saya seperti di bawah ini. Seharusnya ambil seluruh struktur direktori dari dalam direktori saat ini dan direplikasi ke dalamnya $OUTDIR
.
for DIR in `find . -type d -printf "\"%P\"\040"`
do
echo mkdir -p \"${OUTPATH}${DIR}\" # Using echo for debug; working script will simply execute mkdir
echo Created $DIR
done
Masalahnya adalah, ini contoh struktur file saya:
$ ls
Expect The Impossible-Stellar Kart
Five Iron Frenzy - Cheeses...
Five Score and Seven Years Ago-Relient K
Hello-After Edmund
I Will Go-Starfield
Learning to Breathe-Switchfoot
MMHMM-Relient K
Catat spasi: -S Dan for
ambil parameter kata demi kata, jadi output skrip saya terlihat seperti ini:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Learning"
Created Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot"
Created Breathe-Switchfoot
Tapi saya membutuhkannya untuk mengambil seluruh nama file (satu baris pada satu waktu) dari output find
. Saya juga telah mencoba membuat find
tanda kutip ganda di setiap nama file. Tetapi ini tidak membantu.
for DIR in `find . -type d -printf "\"%P\"\040"`
Dan output dengan baris yang diubah ini:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"""
Created ""
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"Learning"
Created "Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot""
Created Breathe-Switchfoot"
Sekarang, saya perlu beberapa cara yang bisa saya ulangi seperti ini, karena saya juga ingin menjalankan perintah yang lebih rumit yang melibatkan gstreamer
setiap file dalam struktur serupa berikut. Bagaimana saya harus melakukan ini?
Sunting: Saya memerlukan struktur kode yang akan memungkinkan saya menjalankan beberapa baris kode untuk setiap direktori / file / loop. Maaf jika saya tidak jelas.
Solusi: Saya awalnya mencoba:
find . -type d | while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done
Ini berfungsi dengan baik untuk sebagian besar. Namun, saya kemudian menemukan bahwa karena pipa menghasilkan loop sementara berjalan dalam subkulit, variabel apa pun yang ditetapkan dalam loop kemudian tidak tersedia yang membuat menerapkan penghitung kesalahan cukup sulit. Solusi terakhir saya (dari jawaban ini di SO ):
while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done < <(find . -type d)
Ini kemudian memungkinkan saya untuk menambahkan variabel secara kondisional dalam loop yang akan tetap tersedia nanti dalam skrip.
/
karakter yang tidak diinginkan. Tapi apa pun diperbolehkan kecuali/
dan\0
sehingga Anda harus membiarkan mereka.Jawaban:
Anda perlu menyalurkannya ke
find
dalam satuwhile
lingkaran.Juga, Anda tidak perlu menggunakan
-printf
dalam hal ini.Anda dapat membuat bukti ini terhadap file dengan baris baru di namanya, jika Anda mau, dengan menggunakan pembatas nullbyte (yang menjadi satu-satunya karakter yang tidak dapat muncul dalam * nix filepath):
Anda juga akan menemukan bahwa menggunakan
$()
backtick lebih fleksibel dan lebih mudah. Mereka dapat bersarang jauh lebih mudah dan mengutip dapat dilakukan dengan lebih mudah. Contoh yang dibuat-buat ini akan menggambarkan poin-poin ini:Coba lakukan itu dengan backticks.
sumber
"$dir"
itu, lebih baik digunakan"${dir}"
- lebih mudah untuk membedakan antara $ {dir} name dan $ {dirname}, tetapi $ dirname dapat diartikan dengan cara apa pun.read
membaca seluruh baris${dir}
, sehingga IFS tidak masalah.find … -print0 | xargs -0 …
karena pembatas yang digunakan sesuai persis dengan satu-satunya karakter yang tidak diperbolehkan dalam pathanames POSIX: NUL (U + 0000).while
. @ Chris Johnsen: Benar, tetapi bahkan program ripping musik tidak cenderung memasukkan umpan baris ke nama file mereka. Dan jika mereka melakukannya, saya ingin tahu (yaitu: ada yang tidak beres) dan segera singkirkan mereka ...Lihat jawaban ini yang saya tulis beberapa hari lalu untuk contoh skrip yang menangani nama file dengan spasi.
Ada cara yang sedikit lebih berbelit-belit (tetapi lebih ringkas) untuk mencapai apa yang Anda coba lakukan:
-print0
memberitahu find untuk memisahkan argumen dengan null; -0 ke xargs memerintahkannya untuk mengharapkan argumen yang dipisahkan oleh nol Ini berarti bahwa ia menangani ruang dengan baik.-I {}
memberitahu xargs untuk mengganti string{}
dengan nama file. Ini juga menyiratkan bahwa hanya satu nama file yang harus digunakan per baris perintah (xargs biasanya akan memuat sebanyak yang sesuai pada baris)Sisanya harus jelas.
sumber
Masalah yang Anda temui adalah pernyataan for sedang merespons temuan sebagai argumen terpisah. Pembatas ruang. Anda perlu menggunakan variabel IFS bash untuk tidak terpecah pada ruang.
Berikut ini tautan yang menjelaskan cara melakukan ini.
Setel temuan Anda untuk menghasilkan pembatas bidang Anda setelah% P dan setel IFS Anda dengan tepat. Saya memilih semi-colon karena sangat tidak mungkin ditemukan di nama file Anda.
Alternatif lain adalah memanggil mkdir dari find secara langsung via
-exec
do Anda dapat melewatkan for for loop sama sekali. Itu jika Anda tidak perlu melakukan parsing tambahan.sumber
/
pada POSIX, dan:
pada sistem file DOS. Ada karakter ilegal untuk berbagai sistem file yang dapat Anda pilih untuk IFS. Ada yang lebih rumit dan Anda lebih baik menggunakan perl.find
mengembalikan nama file dengan path termasuk slash. Coba ubah tanda titik koma di skrip Anda menjadi garis miring dan gema akan mencetak direktori dan nama file pada baris terpisah.while
, tetapi ini juga terlihat cukup bisa diterapkan. Ya, dalam struktur serupa saya nanti saya perlu melakukan parsing lebih lanjut. (Nama file input akan menjadi .ogg, yang akan dilewatkan sepertifilesrc
pada pipa gst, tetapi akhiran yang setara dengan .mp3 yang didasarkan pada direktori keluaran akan dihasilkan dan juga diteruskan ke pipa sebagaifilesink
, dan ini tentu saja perlu dilakukan untuk setiap file, bersama dengan beberapaecho
ke pengguna.)Jika isi loop Anda lebih dari satu perintah, dimungkinkan untuk menggunakan xargs untuk menggerakkan skrip shell:
Pastikan untuk menyertakan tanda hubung trailing (atau 'kata' lain) jika shellnya dari varietas Bourne / POSIX (digunakan untuk menetapkan $ 0 dalam skrip shell). Juga, harus diperhatikan dengan mengutip, karena skrip shell sedang ditulis di dalam string yang dikutip, bukan langsung pada prompt.
sumber
dalam pertanyaan Anda yang telah diperbarui
ini seharusnya
sumber
sumber
atau untuk membuat semuanya jauh lebih rumit:
ini mereplikasi struktur direktori SRC ke DST.
sumber
while
...do
...done
nanti untuk melakukan pemrosesan serupa dari find, yang akan membutuhkan beberapa baris kode untuk dijalankan pada setiap file (modifikasi string, gema, luncurkan gst, dll. ) danrsync
tidak akan mencapai ini. Itu sebabnya saya menentukan bahwa saya harus dapat menjalankan serangkaian perintah yang lebih rumit dalam strucutre yang sama. Script saya menggunakan struktur loop ini dua kali, jadi untuk pertanyaan saya memposting satu dengan kurang kasar di tengah.Jika Anda menginstal GNU Parallel http: // www.gnu.org/software/parallel/ Anda dapat melakukan ini:
Tonton video intro untuk GNU Parallel untuk mempelajari lebih lanjut: http://www.youtube.com/watch?v=OpaiGYxkSuQ
sumber