Her şeyi yeniden yapacak yüreğim yok ama bunu Commandline Find Sed Exec'e cevabım olarak yazdım . Orada soruyu soran kişi, muhtemelen bir veya iki dizini hariç tutarak bir ağacın tamamını nasıl taşıyacağını ve "OLD" dizesini içeren tüm dosya ve dizinleri "NEW" içerecek şekilde yeniden adlandırmayı istedi .
Aşağıdaki özenli ayrıntılarla nasıl anlatılacağını açıklamanın yanı sıra , bu yöntem yerleşik hata ayıklamayı içerdiği için de benzersiz olabilir. Temelde, istenen işi gerçekleştirmek için yapması gerektiğine inandığı tüm komutları derlemek ve bir değişkene kaydetmek dışında hiçbir şey yazmaz.
Ayrıca , döngüleri olabildiğince açık bir şekilde önler . Ayrıca sedbirden fazla maç için özyinelemeli arama deseni bildiğim kadarıyla olarak başka Yinelemesiz yoktur.
Ve son olarak, bu tamamen nullsınırlandırılmıştır - herhangi bir dosya adında null. Buna sahip olman gerektiğini düşünmüyorum.
Bu arada, bu GERÇEKTEN hızlı. Bak:
% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}"
> read -r SED <<SED
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*[\t]\(mv.*\)${5}|\1|p
> SED
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" |
> sort -zg | sed -nz ${SED} | read -r ${6}
> echo <<EOF
> Prepared commands saved in variable: ${6}
> To view do: printf ${6} | tr "\000" "\n"
> To run do: sh <<EORUN
> $(printf ${6} | tr "\000" "\n")
> EORUN
> EOF
> }
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}"
% time ( _mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \
> | wc - ; echo ${sh_io} | tr "\000" "\n" | tail -n 2 )
<actual process time used:>
0.06s user 0.03s system 106% cpu 0.090 total
<output from wc:>
Lines Words Bytes
115 362 20691 -
<output from tail:>
mv .config/replacement_word-chrome-beta/Default/.../googlestars \
.config/replacement_word-chrome-beta/Default/.../replacement_wordstars
NOT: Yukarıdakiler functionbüyük olasılıkla ve ve çağrılarının düzgün şekilde GNUişlenmesi için sedve sürümlerini gerektirecektir . Bunlar sizin için mevcut değilse, işlevsellik birkaç küçük ayarlamayla büyük olasılıkla kopyalanabilir.findfind printfsed -z -e:;recursive regex test;t
Bu, baştan sona istediğiniz her şeyi çok az telaşla yapmalıdır. Yaptığım forkile sed, ama aynı zamanda bazı pratik yapıyordum sedben bu yüzden buradayım yıllardan bu kadar özyinelemeli dallanma teknikleri. Bir berber okulunda indirimli saç kesimi yapmak gibi sanırım. İşte iş akışı:
rm -rf ${UNNECESSARY}
- Her türlü veriyi silebilecek veya yok edebilecek herhangi bir işlevsel çağrıyı kasıtlı olarak dışarıda bıraktım. Bunun
./appistenmeyen olabileceğini söylüyorsunuz. Önceden silin veya başka bir yere taşıyın ya da alternatif olarak bunu programlı olarak yapmak için bir \( -path PATTERN -exec rm -rf \{\} \)rutin oluşturabilirsiniz find, ancak bu tamamen sizin.
_mvnfind "${@}"
- Argümanlarını bildirin ve worker (işçi) işlevini çağırın.
${sh_io}işlevin getirisini kaydetmesi açısından özellikle önemlidir. ${sed_sep}yakın bir saniyede gelir; bu, sedişlevdeki özyinelemesine başvurmak için kullanılan rastgele bir dizedir . Eğer ${sed_sep}potansiyel olarak Path- veya üzerine ... iyi, sadece olmasına izin verme davrandı dosya adlarından herhangi bulunabilir olabilecek bir değere ayarlanır.
mv -n $1 $2
- Ağacın tamamı baştan taşınır. Çok fazla baş ağrısını kurtaracak; inan bana. Yapmak istediklerinizin geri kalanı - yeniden adlandırma - sadece bir dosya sistemi meta verisi meselesidir. Örneğin, bunu bir sürücüden diğerine veya herhangi bir dosya sistemi sınırının ötesine taşıyorsanız, bunu tek bir komutla yapmanız daha iyi olur. Aynı zamanda daha güvenlidir. Aşağıdakiler için
-noclobberayarlanan seçeneğe dikkat edin mv; yazıldığı gibi, bu işlev zaten var olan ${SRC_DIR}yere koymayacaktır ${TGT_DIR}.
read -R SED <<HEREDOC
- Kaçan güçlüklerden tasarruf etmek için tüm sed komutlarını burada buldum ve aşağıda sed'i beslemek için bunları bir değişkene okudum. Aşağıdaki açıklama.
find . -name ${OLD} -printf
- Biz başlamak
findsüreci. İle findsadece yeniden adlandırılması gereken herhangi bir şeyi ararız çünkü tüm yer-yer mvişlemleri fonksiyonun ilk komutuyla zaten yaptık . Örneğin findbir execçağrı gibi herhangi bir doğrudan eylemde bulunmak yerine, komut satırını dinamik olarak oluşturmak için kullanırız -printf.
%dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
findİhtiyacımız olan dosyaları bulduktan sonra , doğrudan yeniden adlandırmanızı işlememiz gereken komutun ( çoğunu ) oluşturur ve yazdırır . %dir-depthHer satırın başlangıcı henüz yeniden adlandırılması olduğu üst nesneyle ağacında bir dosya veya dizini yeniden adlandırmak için çalışmıyoruz sağlamaya yardımcı olur tacked. finddosya sistemi ağacınızda gezinmek için her türlü optimizasyon tekniğini kullanır ve ihtiyacımız olan verileri işlemler için güvenli bir sırada döndüreceği kesin değildir. Bu yüzden sıradaki ...
sort -general-numerical -zero-delimited
- $ {SRC} ile ilişkide en yakın yollar önce çalışılacak şekilde tüm
findçıktılarını %directory-depthsıralarız. Bu mv, dosyaların var olmayan konumlara dahil edilmesiyle ilgili olası hataları önler ve yinelemeli döngü ihtiyacını en aza indirir. ( aslında, bir döngü bulmakta zorlanabilirsiniz )
sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
- Bence bu, tüm komut dosyasındaki tek döngü ve
%Pathdeğiştirilmesi gerekebilecek birden fazla $ {OLD} değeri içermesi durumunda, her dizge için yazdırılan ikinci döngüde yalnızca döngü oluyor . Hayal ettiğim tüm diğer çözümler ikinci bir sedsüreci içeriyordu ve kısa bir döngü arzu edilmeyebilirken, kesinlikle tüm bir sürecin ortaya çıkmasını ve çatallanmasını yener.
- Yani temelde
sedburada yapılan, $ {sed_sep} için arama yapmaktır, o zaman, onu bulduktan sonra, onu ve karşılaştığı tüm karakterleri $ {OLD} bulana kadar kaydeder, sonra onu $ {NEW} ile değiştirir. Daha sonra $ {sed_sep} 'e geri döner ve dizede birden fazla olması durumunda $ {OLD} için tekrar arar. Bulunmazsa, değiştirilen dizeyi yazdırır stdout(daha sonra tekrar yakalar) ve döngüyü sona erdirir.
- Bu, tüm dizeyi ayrıştırma zorunluluğunu ortadan kaldırır ve
mvelbette $ {OLD} içermesi gereken komut dizesinin ilk yarısının bunu içermesini ve ikinci yarısının da silmek için gerektiği kadar değiştirilmesini sağlar. mvHedef yolundan $ {OLD} adı .
sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
- Buradaki iki
-execçağrı bir saniye olmadan gerçekleşir fork. İlkinde, gördüğümüz mvgibi , $ {OLD} ile $ {NEW} arasındaki tüm referansları düzgün bir şekilde değiştirmek için find's -printffunction komutunun sağladığı komutu gerektiği gibi değiştirdik, ancak bunu yapmak için bazılarını kullanmalıydık nihai çıktıya dahil edilmemesi gereken keyfi referans noktaları. Yani sedyapması gereken her şeyi bitirdiğinde, ona geçmeden önce bekleme tamponundaki referans noktalarını silmesi talimatını veriyoruz.
VE ŞİMDİ ETRAFTAYIZ
read şuna benzer bir komut alacak:
% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000
Olacak readiçine ${msg}olarak ${sh_io}işlev irade dışarıdan muayene edilebileceği.
Güzel.
-Mike