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ı?
pr
bunun 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ı?
pr
bunun 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 sed
tamam 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"' {} \;
expand
geçerli dizin ağacındaki her Java dosyasına uygulanır . -name
Başka dosya türlerini hedefliyorsanız argümanı kaldırın / değiştirin . Yorumlardan biri olarak, -name
zayı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.
{}
. $0
Ne zaman -c
kullanı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 /tmp
daha yavaş olacak şekilde değiştirildi /tmp
. Maalesef $0
teklifinizi 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"' {} \;
sponge
gelen 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).sponge
dan moreutils
paketin kaçındığını ve giriş dosyasını temizleyerek .Son olarak, Homebrew ( ) ile gexpand
kurduktan sonra OSX'te kullanabilirsiniz .coreutils
brew install coreutils
-i
için expand
adresine geçmelisiniz . Bu, kodun bir parçası olabilecek sekmelerin değiştirilmesini önlemeye yardımcı olur.
input
aynı dosya, output
baş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 sponge
gelen 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-iname
Bir vaka duyarsız maçı (hem içindir *.java
ve *.JAVA
sever)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şletirsponge
standart 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 tmp
dosyalar 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' *.txt
Tüm * .txt dosyalarında tüm sekmeleri yerinde 1 boşlukla değiştirin:
sed -i $'s/\t/ /g' *.txt
Tüm * .txt dosyalarında tüm sekmeleri yerinde 4 boşlukla değiştirin:
sed -i $'s/\t/ /g' *.txt
Mac'te:
Tüm * .txt dosyalarında tüm sekmeleri yerinde 4 boşlukla değiştirin:
sed -i '' $'s/\t/ /g' *.txt
sed -i '' $'s/\t/ /g' $(find . -name "*.txt")
Genel olarak kullanılabilir pr
komutu 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=num
sekmeleri num
boş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:
expand
ikisinin 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, find
kullandığı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:
expand
bunu 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\n
ile \n
, bir sondaki ekleyerek \n
vb
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
, sh
komutun 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_MAX
uzun olabilir. Bu, Linux sistemlerinde 128 bin, ancak bu sınırı kabuk globbing'e güvenmemek için yeterince kez karşılaştım.
find
söylenebilir -maxdepth 1
ve sadece değiştirilen dizinin girişlerini işler, tüm ağacı değil.
astyle
Karma 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, vim
ayarları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.
:retab
dosyadaki tüm sekmeleri değiştirir, başlangıçtaki sekmeleri değiştirmez. aynı zamanda sizin :tabstop
ve :expandtab
ayarlarınızın vimrc veya modelinde ne olduğuna bağlıdır , bu yüzden bu hiç işe yaramayabilir.
tabstop
Ve expandtab
ayarları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:
sed
bir akış düzenleyicisidir. ex
Yerinde 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|xargs
yerine 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 .ex
her Unix sisteminde mevcut olmayabilir. Bunun yerine vi -e
koymak 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
xargs
Bu ş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 -exec
yerine 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 find
birlikte 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 tab
karakterdeki her karakteri 2 ile değiştirir spaces
.
Hiç vücuttan bahsedilmedi rpl
mi? 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ı expand
diğ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 ''
:
.git
açıklandığı gibi: Git deposundaki tüm metin (ikili olmayan) dosyalar nasıl listelenir?
chmod --reference
dosya 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 4
sekmeyi olması a\tb
gerektiği gibi 3 boşluğa ve aa\tb
2 boşluğa genişletir . expand
sekmenin içeriğini dikkate alır, bağlamdan sed
bağı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 ex
editör + expand
yardı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 $*
}
:retab
hiç işe yaramayabilir , kabuk globbing bu tür bir şey için kötü bir çözümdür , :s
komutunuz herhangi bir sekme miktarını 2 boşlukla değiştirecektir (ki neredeyse asla istemiyorum), sadece bir :!expand
işlemi yürütmek için eski başlamak aptalca ...