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 sed
birden fazla maç için özyinelemeli arama deseni bildiğim kadarıyla olarak başka Yinelemesiz yoktur.
Ve son olarak, bu tamamen null
sı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 function
büyük olasılıkla ve ve çağrılarının düzgün şekilde GNU
işlenmesi için sed
ve sürümlerini gerektirecektir . Bunlar sizin için mevcut değilse, işlevsellik birkaç küçük ayarlamayla büyük olasılıkla kopyalanabilir.find
find printf
sed -z -e
:;recursive regex test;t
Bu, baştan sona istediğiniz her şeyi çok az telaşla yapmalıdır. Yaptığım fork
ile sed
, ama aynı zamanda bazı pratik yapıyordum sed
ben 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
./app
istenmeyen 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, sed
iş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
-noclobber
ayarlanan 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
find
süreci. İle find
sadece yeniden adlandırılması gereken herhangi bir şeyi ararız çünkü tüm yer-yer mv
işlemleri fonksiyonun ilk komutuyla zaten yaptık . Örneğin find
bir 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-depth
Her 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. find
dosya 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-depth
sı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
%Path
değ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 sed
sü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
sed
burada 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
mv
elbette $ {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. mv
Hedef 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 mv
gibi , $ {OLD} ile $ {NEW} arasındaki tüm referansları düzgün bir şekilde değiştirmek için find
's -printf
function 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 sed
yapması 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 read
içine ${msg}
olarak ${sh_io}
işlev irade dışarıdan muayene edilebileceği.
Güzel.
-Mike