Sekmeleri bir dizinin her dosyasındaki boşluklara nasıl dönüştürebilirim (muhtemelen yinelemeli olarak)?
Ayrıca, sekme başına boşluk sayısını ayarlamanın bir yolu var mı?
prbunun için harika bir yardımcı programdır. Bu cevaba bakınız .
Sekmeleri bir dizinin her dosyasındaki boşluklara nasıl dönüştürebilirim (muhtemelen yinelemeli olarak)?
Ayrıca, sekme başına boşluk sayısını ayarlamanın bir yolu var mı?
prbunun için harika bir yardımcı programdır. Bu cevaba bakınız .
Yanıtlar:
Uyarı: Bu deponuzu kıracak.
Bu irade bozuk ikili dosyalar olanlar under dahil
svn,.git! Kullanmadan önce yorumları okuyun!
find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +
Orijinal dosya olarak kaydedilir [filename].orig.
'* .Java' yerine, aradığınız dosya türünün dosya sonu ile değiştirin. Bu şekilde, ikili dosyaların yanlışlıkla bozulmasını önleyebilirsiniz.
Downsides:
expand.
find ./ -type f -exec sed -i 's/^\t/####/g' {} \;. Ama genişlet komutunun farkında değildim - çok kullanışlı!
İle basit değiştirme sedtamam ama mümkün olan en iyi çözüm değil. Sekmeler arasında "fazladan" boşluk varsa, ikame edildikten sonra hala orada olurlar, böylece kenar boşlukları düzensizleşir. Satırların ortasında genişletilen sekmeler de düzgün çalışmaz. Yerine bash, diyebiliriz
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
expandgeçerli dizin ağacındaki her Java dosyasına uygulanır . -nameBaşka dosya türlerini hedefliyorsanız argümanı kaldırın / değiştirin . Yorumlardan biri olarak, -namezayıf, joker karakteri kaldırırken veya kullanırken çok dikkatli olun . Depoyu ve diğer gizli dosyaları niyet olmadan kolayca gizleyebilirsiniz. Bu yüzden orijinal cevap şunları içeriyordu:
Bir şeyler ters gittiğinde böyle bir şey denemeden önce daima ağacın yedek bir kopyasını almalısınız.
{}. $0Ne zaman -ckullanıldığını bilmiyor gibi görünüyor . Daha sonra dimo414, dönüşüm dizinindeki bir temp'i kullanmamdan farklı bir bağlama noktasındaysa /tmpdaha yavaş olacak şekilde değiştirildi /tmp. Maalesef $0teklifinizi test edecek bir Linux kutum yok. Ama bence haklısın.
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
spongegelen joeyh.name/code/moreutils yazabilirsinizfind . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
find . -name '*', sadece yerel git repo'yu yok ettim
Komut satırı aracını deneyin expand.
expand -i -t 4 input | sponge output
nerede
-i her satırda yalnızca önde gelen sekmeleri genişletmek için kullanılır;-t 4 her sekmenin 4 boşluk karakterine dönüştürüleceği anlamına gelir (varsayılan olarak 8).spongedan moreutilspaketin kaçındığını ve giriş dosyasını temizleyerek .Son olarak, Homebrew ( ) ile gexpandkurduktan sonra OSX'te kullanabilirsiniz .coreutilsbrew install coreutils
-iiçin expandadresine geçmelisiniz . Bu, kodun bir parçası olabilecek sekmelerin değiştirilmesini önlemeye yardımcı olur.
inputaynı dosya, outputbaşlamadan önce içeriği hızlandırır expand. İşte böyle >çalışır.
En iyi bir yorum Toplama Gene'in cevap , çok iyi çözümü kullanmaktır spongegelen moreutils .
sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;
Açıklama:
./ geçerli dizinden yinelemeli olarak arama yapıyor-inameBir vaka duyarsız maçı (hem içindir *.javave *.JAVAsever)type -f yalnızca normal dosyaları bulur (dizin, ikili dosya veya simge bağlantısı yoktur)-exec bash -c her dosya adı için alt kabukta aşağıdaki komutları yürütebilir, {}expand -t 4 tüm SEKMELER'i 4 boşluğa genişletirspongestandart girişi (itibaren expand) ıslatın ve bir dosyaya (aynı olan) yazın *.NOT : * Basit bir dosya yönlendirmesi ( > "$0") burada çalışmaz çünkü dosyanın üzerine çok erken yazılır .
Avantajı : Tüm orijinal dosya izinleri korunur ve ara tmpdosyalar kullanılmaz.
Ters eğik çizgiden kaçın sed.
Linux'ta:
Tüm sekmeleri tüm * .txt dosyalarında 1 tire ile değiştirin:
sed -i $'s/\t/-/g' *.txtTüm * .txt dosyalarında tüm sekmeleri yerinde 1 boşlukla değiştirin:
sed -i $'s/\t/ /g' *.txtTüm * .txt dosyalarında tüm sekmeleri yerinde 4 boşlukla değiştirin:
sed -i $'s/\t/ /g' *.txtMac'te:
Tüm * .txt dosyalarında tüm sekmeleri yerinde 4 boşlukla değiştirin:
sed -i '' $'s/\t/ /g' *.txtsed -i '' $'s/\t/ /g' $(find . -name "*.txt")
Genel olarak kullanılabilir prkomutu kullanabilirsiniz (kılavuz sayfa burada ). Örneğin, sekmeleri dört boşluğa dönüştürmek için şunu yapın:
pr -t -e=4 file > file.expanded
-t başlıkları bastırır-e=numsekmeleri numboşluklara genişletirİkili dosyaları atlarken dizin ağacındaki tüm dosyaları özyinelemeli olarak dönüştürmek için:
#!/bin/bash
num=4
shopt -s globstar nullglob
for f in **/*; do
[[ -f "$f" ]] || continue # skip if not a regular file
! grep -qI "$f" && continue # skip binary files
pr -t -e=$num "$f" > "$f.expanded.$$" && mv "$f.expanded.$$" "$f"
done
İkili dosyaları atlamanın mantığı bu yayındandır .
NOT:
expandikisinin de POSIX olması avantajı var mı? Örneğin, satır içi değiştirme seçeneği var mı? Git güvenliği
Sekmeleri bir dizinin her dosyasındaki boşluklara nasıl dönüştürebilirim (muhtemelen yinelemeli olarak)?
Bu genellikle istediğiniz şey değildir .
Png resimleri için bunu yapmak ister misiniz? PDF dosyaları? .Git dizini? Sizin
Makefile( sekmeleri gerektiren )? 5GB'lık bir SQL dökümü mü?
Teorik olarak, findkullandığınız herhangi bir şeye veya başka herhangi bir şeye dışlama seçenekleri sunabilirsiniz ; ancak bu kırılgandır ve diğer ikili dosyaları ekler eklemez kırılır.
İstediğiniz, en azından:
expandbunu yapar, sed
yapmaz).Bildiğim kadarıyla, bunu yapabilen bir "standart" Unix yardımcı programı yoktur ve bir kabuk bir astar ile yapmak çok kolay değildir, bu yüzden bir komut dosyası gereklidir.
Bir süre önce tam olarak bunu yapan sanitize_files adlı küçük bir senaryo oluşturdum
. Aynı zamanda değiştirilmesi gibi bazı diğer ortak şeyler düzeltir \r\nile \n, bir sondaki ekleyerek \nvb
Aşağıdaki ekstra özellikler ve komut satırı bağımsız değişkenleri olmadan basitleştirilmiş bir komut dosyası bulabilirsiniz , ancak bu komuttan daha fazla hata düzeltmesi ve diğer güncellemeleri alma olasılığı daha yüksek olduğundan yukarıdaki komut dosyasını kullanmanızı öneririz.
Ayrıca, buradaki diğer cevapların bazılarına yanıt olarak, kabuk globbing kullanmanın bunu yapmanın sağlam bir yolu olmadığını belirtmek isterim , çünkü er ya da geç sığacak daha fazla dosyaya sahip olacaksınız ARG_MAX(modern Linux sistemleri 128k, bu çok görünebilir, ancak er ya da geç
yeterli değildir ).
#!/usr/bin/env python
#
# http://code.arp242.net/sanitize_files
#
import os, re, sys
def is_binary(data):
return data.find(b'\000') >= 0
def should_ignore(path):
keep = [
# VCS systems
'.git/', '.hg/' '.svn/' 'CVS/',
# These files have significant whitespace/tabs, and cannot be edited
# safely
# TODO: there are probably more of these files..
'Makefile', 'BSDmakefile', 'GNUmakefile', 'Gemfile.lock'
]
for k in keep:
if '/%s' % k in path:
return True
return False
def run(files):
indent_find = b'\t'
indent_replace = b' ' * indent_width
for f in files:
if should_ignore(f):
print('Ignoring %s' % f)
continue
try:
size = os.stat(f).st_size
# Unresolvable symlink, just ignore those
except FileNotFoundError as exc:
print('%s is unresolvable, skipping (%s)' % (f, exc))
continue
if size == 0: continue
if size > 1024 ** 2:
print("Skipping `%s' because it's over 1MiB" % f)
continue
try:
data = open(f, 'rb').read()
except (OSError, PermissionError) as exc:
print("Error: Unable to read `%s': %s" % (f, exc))
continue
if is_binary(data):
print("Skipping `%s' because it looks binary" % f)
continue
data = data.split(b'\n')
fixed_indent = False
for i, line in enumerate(data):
# Fix indentation
repl_count = 0
while line.startswith(indent_find):
fixed_indent = True
repl_count += 1
line = line.replace(indent_find, b'', 1)
if repl_count > 0:
line = indent_replace * repl_count + line
data = list(filter(lambda x: x is not None, data))
try:
open(f, 'wb').write(b'\n'.join(data))
except (OSError, PermissionError) as exc:
print("Error: Unable to write to `%s': %s" % (f, exc))
if __name__ == '__main__':
allfiles = []
for root, dirs, files in os.walk(os.getcwd()):
for f in files:
p = '%s/%s' % (root, f)
if do_add:
allfiles.append(p)
run(allfiles)
Yinelemeli uygulama için yukarıdaki "find" örneğini seviyorum. Yinelemeli olmayacak şekilde uyarlamak için, yalnızca geçerli dizindeki joker karakterle eşleşen dosyaları değiştirmek için kabuk glob genişletmesi küçük miktarlardaki dosyalar için yeterli olabilir:
ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
Çalıştığından emin olduktan sonra sessiz olmasını istiyorsanız -v, shkomutun sonunda bırakın .
Tabii ki ilk komutta herhangi bir dosya grubunu seçebilirsiniz. Örneğin, yalnızca belirli bir alt dizini (veya dizinleri) aşağıdaki gibi denetimli bir biçimde listeleyin:
ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
Ya da find (1) 'i bazı derinlik parametrelerinin kombinasyonu ile çalıştırın:
find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
ARG_MAXuzun olabilir. Bu, Linux sistemlerinde 128 bin, ancak bu sınırı kabuk globbing'e güvenmemek için yeterince kez karşılaştım.
findsöylenebilir -maxdepth 1ve sadece değiştirilen dizinin girişlerini işler, tüm ağacı değil.
astyleKarma sekmeler ve boşluklar bulduktan sonra tüm C / C ++ kodumu yeniden girintili olarak kullandım . Ayrıca, isterseniz belirli bir küme ayracı stilini zorlama seçeneklerine de sahiptir.
Bunun için kullanılabilir vim:
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Carpetsmoker'in belirttiği gibi, vimayarlarınıza göre yeniden ayarlanacaktır. Ve varsa dosyalarda modelinler. Ayrıca, sekmeleri yalnızca satırların başında değil. Bu genellikle istediğiniz şey değildir. Örneğin, sekmeler içeren değişmez değerleriniz olabilir.
:retabdosyadaki tüm sekmeleri değiştirir, başlangıçtaki sekmeleri değiştirmez. aynı zamanda sizin :tabstopve :expandtabayarlarınızın vimrc veya modelinde ne olduğuna bağlıdır , bu yüzden bu hiç işe yaramayabilir.
tabstopVe expandtabayarlarına gelince , kullanıyorsanız bu işe yarayacaktır vim. Dosyalarda mod satırları yoksa.
Benim tavsiyem:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
Yorumlar:
sedbir akış düzenleyicisidir. exYerinde düzenleme için kullanın . Bu, üst yanıtta olduğu gibi her değiştirme için ekstra geçici dosyalar oluşturmayı ve kabukları oluşturmayı önler .find|xargsyerine bu cevabın önceki bir sürümü kullanıldı find -exec. @ Gniourf-gniourf tarafından işaret edildiği gibi, bu dosya adlarında boşluklar, tırnak işaretleri ve kontrol karakterleriyle ilgili sorunlara yol açar. Wheeler .exher Unix sisteminde mevcut olmayabilir. Bunun yerine vi -ekoymak daha fazla makinede işe yarayabilir. Ayrıca, normal ifadeniz herhangi bir sayıda başlangıç sekmesi karakterini iki boşlukla değiştirir. +%s/\t/ /gÇok düzeyli girinti yok etmek için normal ifadeyi değiştirin . Ancak bu, girinti için kullanılmayan sekme karakterlerini de etkiler.
/\t/ /benim dosyalar üzerinde varyantı, ama seçti /\t\+//olmayan girinti çıkıntıları kırmak değil. Çoklu girintili sorunları kaçırdınız! Cevabı Güncelleme. [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
xargsBu şekilde kullanmak işe yaramaz, verimsiz ve kırılmıştır (boşluk veya tırnak içeren dosya adlarını düşünün). Neden kullanmayın find'ın -execyerine anahtarını?
-print0/ xargs bulma seçenekleri. Ben xargs sevdim -execçünkü: a) Endişelerin ayrılması b) GNU paralel ile daha kolay değiştirilebilir.
Bir dizindeki tüm Java dosyalarını özyinelemeli olarak sekme yerine 4 boşluk kullanmak üzere dönüştürmek için:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
Bunun için paketle findbirlikte kullanabilirsiniz tabs-to-spaces.
İlk olarak, yükleyin tabs-to-spaces
npm install -g tabs-to-spaces
sonra bu komutu projenizin kök dizininden çalıştırın;
find . -name '*' -exec t2s --spaces 2 {} \;
Bu, her tabkarakterdeki her karakteri 2 ile değiştirir spaces.
Hiç vücuttan bahsedilmedi rplmi? Rpl kullanarak herhangi bir dizeyi değiştirebilirsiniz. Sekmeleri boşluklara dönüştürmek için,
rpl -R -e "\t" " " .
Çok basit.
Kullanımı expanddiğer yanıtlar önerilen tek başına bu görev için en mantıklı yaklaşım gibi görünüyor.
Bununla birlikte, diğer bazı modifikasyonları yapmak isteyebileceğiniz durumunda Bash ve Awk ile de yapılabilir.
Bash 4.0 veya üstünü kullanıyorsanız, shopt yerleşkesiglobstar ile özyinelemeli arama yapmak için kullanılabilir **.
GNU Awk sürüm 4.1 veya üstü ile sed gibi "inplace" dosya değişiklikleri yapılabilir:
shopt -s globstar
gawk -i inplace '{gsub("\t"," ")}1' **/*.ext
Sekme başına boşluk sayısını ayarlamak istiyorsanız:
gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
Sabit sekmeleri düz metin dosyalarındaki yumuşak sekmelere özyineli olarak dönüştürmek için aşağıdaki komut dosyasını indirin ve çalıştırın.
Komut dosyasını düz metin dosyalarını içeren klasörün içinden yürütün.
#!/bin/bash
find . -type f -and -not -path './.git/*' -exec grep -Iq . {} \; -and -print | while read -r file; do {
echo "Converting... "$file"";
data=$(expand --initial -t 4 "$file");
rm "$file";
echo "$data" > "$file";
}; done;
Git veri havuzu dostu yöntem
git-tab-to-space() (
d="$(mktemp -d)"
git grep --cached -Il '' | grep -E "${1:-.}" | \
xargs -I'{}' bash -c '\
f="${1}/f" \
&& expand -t 4 "$0" > "$f" && \
chmod --reference="$0" "$f" && \
mv "$f" "$0"' \
'{}' "$d" \
;
rmdir "$d"
)
Geçerli dizinin altındaki tüm dosyalara göre hareket et:
git-tab-to-space
Yalnızca C veya C ++ dosyalarında kullanılabilir:
git-tab-to-space '\.(c|h)(|pp)$'
Bunu büyük olasılıkla sekmeler gerektiren can sıkıcı Makefiles nedeniyle istersiniz.
Komut git grep --cached -Il '':
.gitaçıklandığı gibi: Git deposundaki tüm metin (ikili olmayan) dosyalar nasıl listelenir?
chmod --referencedosya izinlerini değiştirmez: /unix/20645/clone-ownership-and-permissions-from-another-file Maalesef kısa bir POSIX alternatifi bulamıyorum .
Kod tabanınız, dizelerde işlevsel ham sekmelere izin verme konusunda çılgın bir fikre sahipse, şunu kullanın:
expand -i
: ve ardından eğlenceli ile listeleyebilirsiniz satır sekmeler teker teker olmayan tüm başlamasından üzerinden gidiyor olması o sekmeler için git grep mümkün mü?
Ubuntu 18.04'te test edildi.
Sekmeleri yalnızca ".lua" dosyalarındaki boşluğa dönüştürme [sekmeler -> 2 boşluk]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
expand -t 4 input >output)
expand -t 4sekmeyi olması a\tbgerektiği gibi 3 boşluğa ve aa\tb2 boşluğa genişletir . expandsekmenin içeriğini dikkate alır, bağlamdan sedbağımsız olarak sekmeyi belirttiğiniz alan miktarıyla değiştirmez ve değiştirir.
Vim-way kullanın:
$ ex +'bufdo retab' -cxa **/*.*
globstar( **) kullanmak için, ile etkinleştirin shopt -s globstar.**/*.c.Sekmeyi değiştirmek için ekleyin +'set ts=2'.
Ancak aşağı tarafı dizelerin içindeki sekmelerin yerini alabilmesidir .
Yani biraz daha iyi bir çözüm için (ikame kullanarak) şunu deneyin:
$ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.*
Veya exeditör + expandyardımcı programını kullanarak :
$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*
Sondaki boşluklar için bkz: Birden çok dosya için sondaki boşluklar nasıl kaldırılır?
Aşağıdaki işlevi ekleyebilirsiniz .bash_profile:
# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
ex +'set ts=2' +'bufdo retab' -cxa $*
}
:retabhiç işe yaramayabilir , kabuk globbing bu tür bir şey için kötü bir çözümdür , :skomutunuz herhangi bir sekme miktarını 2 boşlukla değiştirecektir (ki neredeyse asla istemiyorum), sadece bir :!expandişlemi yürütmek için eski başlamak aptalca ...