Kesin olarak "Ayrıştırma !" Diyerek bu bağlantıyı belirten cevapları sürekli görüyorum . Bu beni birkaç nedenden dolayı rahatsız ediyor:ls
Görünüşe göre bu bağlantıdaki bilgiler küçük bir soru ile toptan olarak kabul edildi, ancak günlük okumada en azından birkaç hata bulabilirim.
Aynı zamanda, bu bağlantıda belirtilen problemlerin bir çözüm bulma arzusu yaratmadığı anlaşılıyor.
İlk paragraftan itibaren:
...
[ls]
bir dosya listesi sorduğunuzda çok büyük bir sorun var: Unix, boşluk, yeni satırlar, virgüller, boru sembolleri ve kullanmaya çalıştığınız her şeyi içeren bir dosya adındaki hemen hemen her karaktere izin verir. NUL hariç sınırlayıcı. ...ls
dosya adlarını yeni satırlarla ayırır. Adında yeni satırlı bir dosya olana kadar bu iyi. Ve bunun herhangi bir uygulamasını bilmediğim için,ls
dosya isimlerini yeni satırlar yerine NUL karakterleriyle sonlandırabilmenizi sağlar, bu bize güvenli bir şekilde dosya isimlerinin bir listesini alamamıza neden olurls
.
Serseri, değil mi? Nasıl hiç bir yeni satır yeni satır içerebilir veriler için listelenen veri kümesi sonlandırıldı işleyebilir? Peki, bu web sitesindeki soruları cevaplayan insanlar günlük olarak böyle bir şey yapmadıysa, başımızın belada olduğunu düşünebilirim.
Gerçek şu ki, çoğu ls
uygulama aslında çıktılarını ayrıştırmak için çok basit bir api sağlıyor ve bunu farkında bile olmadan hepimiz yapıyoruz. Bir dosya ismini sadece null ile sonlandırmakla kalmaz, bir null ile de başlatabilirsiniz ya da istediğiniz herhangi bir isteğe bağlı dizeyle başlatabilirsiniz. Dahası, bu keyfi dizeleri dosya türü başına atayabilirsiniz . Düşünün lütfen:
LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@
Bkz bu daha fazlası.
Şimdi bu makalenin bir sonraki kısmı beni gerçekten etkiliyor:
$ ls -l
total 8
-rw-r----- 1 lhunath lhunath 19 Mar 27 10:47 a
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a?newline
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a space
Sorun şu ki
ls
, çıkarımdan ne siz, ne de bilgisayar, onun hangi kısımlarının bir dosya adı olduğunu söyleyemez. Her kelime mi? Hayır. Her satır mı? Hayır. Bu sorunun cevabından başka bir cevap yok: söyleyemezsin.Ayrıca nasıl fark
ls
bazen dosya adı veri (bizim durumumuzda, artık geri garbles\n
kelimeler arasında karakteri "a" ve "yeni satır" a içine ? Soru işareti ......
Geçerli dizindeki tüm dosyalar üzerinde sadece yineleme yapmak istiyorsanız, bir
for
döngü ve bir küre kullanın:
for f in *; do
[[ -e $f ]] || continue
...
done
Yazar, bu çağrılar dosya adlarını tahrifine zaman ls
kabuk globs içeren dosya adları listesini döndürür sonra ve bir dosya listesini almak için bir kabuk topak kullanılmasını önerir!
Aşağıdakileri göz önünde bulundur:
printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
. /dev/stdin
ls -1q
f i l e n a m e
file?name
IFS="
" ; printf "'%s'\n" $(ls -1q)
'f i l e n a m e'
'file
name'
POSIX tanımlar-1
ve -q
ls
böylece operandlar:
-q
- Yazdırılamayan dosya adı karakterlerinin her bir örneğini ve<tab>
s'nin soru işareti ('?'
) karakteri olarak yazılmasını zorlayın . Çıktı bir terminal cihazında ise, uygulamalar bu seçeneği varsayılan olarak sağlayabilir.
-1
- (Sayısal rakam bir.) Çıktıyı satır başına bir giriş olmaya zorlar.
Globbing kendi problemleri olmadan değildir - herhangi bir karakterle ?
eşleşir, böylece bir listedeki çoklu eşleşme sonuçları aynı dosyayla birden çok kez eşleşir. Kolayca idare edilir.?
Bu şeyi nasıl yapılacağı da önemli değil - sonuçta yapılması gereken çok şey yok ve aşağıda gösteriliyor - Neden olmasın ilgimi çekti . Düşündüğüm kadarıyla, bu sorunun en iyi cevabı kabul edildi. Ben onlar insanlara ne anlatmaya daha sık odaklanmaya denemenizi öneririm olabilir ne üzerinde başka yapacak olamaz. En azından yanlış olduğunu kanıtlama ihtimalim çok daha az.
Ama neden denesin ki? Kuşkusuz, benim temel motivasyonum, başkalarının bana yapamayacağımı söylemeye devam etmesiydi. Ne ls
kadar aradığınızı bildiğiniz sürece , çıktının istediğiniz kadar düzenli ve tahmin edilebilir olduğunu çok iyi biliyorum. Yanlış bilgilendirme beni çoğu şeyden daha çok rahatsız ediyor.
Gerçek şu ki, hem Patrick'in hem de Wumpus Q'nun kayda değer istisnası dışında. Wumbley'nin cevapları (ikincisinin müthiş kulpuna rağmen) , buradaki cevaplardaki bilgilerin çoğunu çoğunlukla doğru buluyorum - bir kabuk küresi kullanımı daha basit. ve genel olarak mevcut dizini ararken, ayrıştırmaya göre daha etkilidir ls
. Onlar benim konuda en azından yeterli bir sebep ya yukarıdaki makalede alıntı yanlış bilgilendirmeyi çoğaltım ne de kabul edilebilir gerekçe olan haklı, ancak değildir " ayrıştırmak asla ls
. "
Lütfen Patrick'in cevaplarının tutarsız sonuçlarının çoğunlukla zsh
o zaman kullanmasının bir sonucu olduğunu unutmayın bash
. zsh
- varsayılan olarak - sözcük ayırma $(
komutu yerine )
taşınabilir bir şekilde sonuç vermiyor . Peki , dosyaların geri kalanının nereye gittiğini sorduğunda ? Bu sorunun cevabı kabuğun onları yedim. Bu yüzden taşınabilir kabuk kodunu SH_WORD_SPLIT
kullanırken zsh
ve kullanırken değişkenleri ayarlamanız gerekir . Cevabında bunu not etmedeki başarısızlığını çok yanıltıcı olarak görüyorum.
Wumpus cevabı benim için hesaplamak değil - bir liste bağlamında ?
karakter olan bir kabuk glob. Bunu nasıl söyleyeceğimi bilemiyorum.
Birden fazla sonuç elde etmek için, kürenin açgözlülüğünü sınırlamanız gerekir. Aşağıdakiler sadece korkunç dosya adlarının test temelini oluşturacak ve sizin için gösterecektir:
{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin
echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}
ÇIKTI
`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b
NOW LITERAL - COMMA,SEP
?
\, ?
^, ?
`, ?
b, [ \, [
\, ] ^, ]
^, _ `, _
`, a b, a
b
FILE COUNT: 12
Şimdi olacak güvenli bir değil her karakter /slash
, -dash
, :colon
ardından bir kabuk glob içinde veya alfa-sayısal karakter sort -u
benzersiz sonuçlar için listeye. Bu güvenlidir, çünkü ls
bizim için basılabilir olmayan karakterleri zaten güvenli bir şekilde uzaklaştırmıştır. İzlemek:
for f in $(
ls -1q |
sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
sort -u | {
echo 'PRE-GLOB:' >&2
tee /dev/fd/2
printf '\nPOST-GLOB:\n' >&2
}
) ; do
printf "FILE #$((i=i+1)): '%s'\n" "$f"
done
ÇIKTI:
PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b
POST-GLOB:
FILE #1: '?
\'
FILE #2: '?
^'
FILE #3: '?
`'
FILE #4: '[ \'
FILE #5: '[
\'
FILE #6: '] ^'
FILE #7: ']
^'
FILE #8: '_ `'
FILE #9: '_
`'
FILE #10: '?
b'
FILE #11: 'a b'
FILE #12: 'a
b'
Aşağıda soruna tekrar yaklaşıyorum ancak farklı bir metodoloji kullanıyorum. Unutmayın - \0
null dışında - /
ASCII karakteri bir yol adında yasaklanan tek bayttır. Burada küreleri bir kenara koydum ve bunun yerine POSIX için belirtilen -d
seçeneği ls
ve ayrıca belirtilen POSIX -exec $cmd {} +
için yapıyı birleştirdim find
. Çünkü find
sadece hiç doğal olarak bir tane çıkarır /
sırayla, kolayca aşağıdaki her giriş için tüm dentry bilgiler içeren bir özyinelemeli ve güvenilir sınırlandırılmış filelist tedarik etmektedir. Bunun gibi bir şeyle neler yapabileceğinizi hayal edin:
#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'
###OUTPUT
152398 drwxr-xr-x 1 1000 1000 72 Jun 24 14:49
.///testls///
152399 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
\///
152402 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
^///
152405 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
`///
...
ls -i
çok yararlı olabilir - özellikle sonuç benzersizliği söz konusu olduğunda.
ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find
Bunlar, düşünebildiğim en taşınabilir araç. GNU ile ls
yapabilecekleriniz:
ls --quoting-style=WORD
Ve son olarak, burada inode sayılarına ihtiyaç duyduğumda oldukça sık kullandığım ayrıştırmals
yöntemi daha basit :
ls -1iq | grep -o '^ *[0-9]*'
Bu sadece inode numaralarını döndürür - başka bir kullanışlı POSIX tarafından belirtilen seçenek.
stat
, çünkü her dosyanın varlığını kontrol ediyor. sed
Şey ile altındaki bit işe yaramaz.
ls
, ilk etapta ayrıştırmamaktan daha kolay veya basit veya herhangi bir şekilde daha iyi olabilir ? Tarif ettiğiniz şey çok zor. Hepsini anlayabilmem için onu yapılandırmam gerekecek ve nispeten yetkin bir kullanıcıyım. Ortalama Joe'nuzun bunun gibi bir şeyle başa çıkmasını beklemeniz beklenemez.
ls
Çıktının ayrıştırılmasının yanlış olmasının tüm nedenleri orijinal linkte (ve birçok başka yerde) iyi bir şekilde ele alınmıştır. OP bunu anlamak için yardım isterse bu soru uygun olurdu, ancak OP bunun yerine yanlış kullanımının uygun olduğunu kanıtlamaya çalışıyor.
parsing ls is bad
. Yapma for something in $(command)
ve doğru sonuçlar elde etmek için kelime bölme güvenerek büyük çoğunluğu için kötü command's
basit çıkışını bizde olmayan.
time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'
= 3.18s vstime bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'
= 1.28s