Her zaman rm'nin çıkardığı dosyaları listeler mi?


33

İçimden Kesin olarak bildiğim gerektiğini hissediyorum: Ben eğer ls <something>, olacak rm <something>tam olarak aynı dosyaları kaldırmak lsgörüntülenen? Gösterilmeyen rmdosyaları kaldırabilecek durumlar var lsmı? (Bu 18.04 bash'ta)

Düzenleme: cevaplayan herkese teşekkür ederim. Tam cevabın tüm cevapların bir birleşimi olduğunu düşünüyorum, bu yüzden en fazla oyu alan cevabı "cevap" olarak kabul ettim.

Beklenmedik şeyler boyunca öğrendiğim şeyler:

  • ls Argümanlarını ele alırken düşündüğünüz kadar basit değildir
  • Ubuntu kurulumunda basit ve karmaşık olmayan bir kurulumda .bashrc takma adları ls
  • Dosyalarınızı bir çizgi ile başlayan, komut argümanlarına benzeyebilecekleri gibi adlandırmayın ve bir -r'yi isimlendirmek ister!

8
Ben biraz şaşırttı am rma sahip değil --dry-run... bayrak
fkraiem

20
@ Rinzwind Neden daha find -deleteiyi olurdu rm? “Bu yüzden” diyorsunuz , ama bunun neyi kastettiği tam olarak belirsiz. Ayrıca, findçağrınızın geçerli dizindeki art arda silinen dosyaları sileceğini unutmayın; rmbu dosyalar hemen dizin içindeki dosyaları siler. Ayrıca -name *no-op. Sonuç olarak, tavsiyenize oldukça
şaşırdım

3
@ marcelm Bence kullanmanın tavsiyesi findonu çalıştırabilir, tüm dosyaları görebilir ve ardından aynı komutu çalıştırabilirsiniz -delete. Zaten sonuçlarını gördük beri find, (aslında böyle bir cevap şeklinde bu konuda daha fazla ayrıntı duymak istiyorum) silinecektir ne herhangi bir belirsizlik olmalıdır
Scribblemacher

5
@Scribblemacher "... onu çalıştırabilir, tüm dosyaları görebilir ve ardından aynı komutu çalıştırabilirsiniz -delete" - Ama bu nasıl çalışmaktan daha iyi ls <filespec>, ardından rm <filespec>(OP zaten nasıl yapılacağını bilir)?
marcelm

12
@Rinzwind "Bu, choroba'nın ls'den sonra ve rm'den önce bir dosyanın oluşturulduğu anında yanıtını çözer." - Hayır, değil. find ... -printÖnce hangi dosyaların silineceğini onaylamak için çalıştırırsanız , sonra find ... -deleteda iki komut arasında oluşturulan dosyaları sileceksiniz. Her ikisini de kullanırsanız -printve -deleteonay alamazsanız, silinenlerin sadece bir gerçeğe uygun raporu (ve belki de kullanabilirsiniz rm -v).
mart

Yanıtlar:


40

Her ikisi de lsve rmkendilerine verilen argümanlar üzerinde çalışırlar.

Bu argümanlar, böylece basit bir dosya olabilir ls file.extve rm file.extaynı dosya üzerinde işlem ve sonuç açıktır (liste dosyası / dosya silme).

Bunun yerine argüman bir dizin ise, dizinin içeriğini olduğu gibi çalışmayacak şekilde ls directorylisteler (yani bayraklar olmadan dizinleri kaldıramaz, eğer yaparsanız , yinelenerek altındaki tüm dosyaları ve dizinin kendisini siler ).rm directoryrmrm -r directorydirectory

Ama komut satırı argümanları tabi tutulabilir unutmayın kabuk genişleme o değil bu yüzden, her zaman garanti onlar vb diğer komutlar, gelen joker, değişkenler, çıkış içeriyorsa aynı argümanlar hem komutlara yansıtılması anlamına

Aşırı bir örnek olarak düşünün ls $(rand).txtve rm $(rand).txtargümanlar "aynı" dır, ancak sonuçlar oldukça farklıdır!


3
Ayrıca düşünün lsvs rm *ben yazmadım orada "gizli" olan (nokta) dosyalar olsa bile bütün Adil bir karşılaştırma ile en değil ls *. Ama rmkendi başına anlamsız, bu yüzden her şey gerçekten elma ve portakal. Eğer doğru anladıysam, cevabın temel noktası bu, çok iyi bir iş :)
Monica ile Hafiflik Yarışları

5
Bir başka açıklama lsvs rm -rkomut: ls <directory>dizin içinde gizlenmiş dosyaları göstermek olmaz, ama rm -r <directory> olacak hatta gizli dosyaları silin.
Daniel Wagner

1
@LightnessRacesinOrbit lsbunları listeleyemez (diğer adı belirtilmedikçe ls -a) ve rm *bunları silmez ( dotglobayarlamadıysanız).
Monica'ya Zarar Vermeyi Durdur

20

Eğer ls foo*.txtvs. gibi bir şey düşünüyorsanız, rm foo*.txtevet, aynı dosyaları gösterip silerler. Kabuk, küreyi genişletir ve söz konusu komuta iletir ve komutlar listelenen dosyalar üzerinde çalışır. Biri onları listeliyor, biri onları kaldırıyor.

Buradaki belirgin fark, bu dosyalardan herhangi birinin bir dizin lsolması halinde içeriğinin listelenmesi, ancak rmsilinmemesidir. Bu genellikle bir sorun değildir, çünkü gösterilenden daha azını rmkaldıracaktır .ls

Buradaki en büyük sorun çalışan ls *veya bir çizgi ile başlayan dosya adlarınırm * içeren bir dizinden kaynaklanıyor . Onlar kendini onları yazdım sanki iki programların komut hatlarına genişletecek ve lsalacağını -rederken, "ters sıralama düzeni" anlamına rmalacağını -rbir özyinelemeli çıkarılmasını anlamına. Aradaki fark, en az iki seviye derin alt dizinleriniz varsa önemlidir. ( ls *birinci seviye dizinlerin içeriğini gösterecektir, fakat rm -r *ilk alt seviyeyi geçen her şey de olacaktır.)

Bundan kaçınmak için, ./geçerli dizini belirtmek üzere bir öncü içeren izin verilen küreler yazın ve / veya --seçenek işlemeden önce kürenin ( rm ./*veya veya rm -- *) sonunu belirtmek için bir işaret koyun .

Gibi bir glob ile *.txt, nokta geçersiz bir seçenek karakteri olduğundan ve bu bir hataya neden olacağından (birisi bunun için bir anlam icat eden hizmetleri genişletene kadar) bir sorun yaratır, ancak yine de ./oraya koymak daha güvenlidir .


Elbette, kabuğun globbing seçeneklerini değiştirdiyseniz ya da komutlar arasında yer alan / taşınan / kaldırılan dosyalar oluşturduysanız, iki komut için farklı sonuçlar elde edebilirsiniz, ancak bu durumlardan herhangi birini kastettiğinizden şüpheliyim. (Yeni / taşınan dosyalarla çalışmak, güvenli bir şekilde yapılması son derece karışık olacaktır.)


1
Teşekkür ederim. Bu, komut satırı söz diziminin tamamı ile ilgili bir sorunu vurgulamaktadır: bir çizgi ile başlayan dosyaları isimlendirirseniz tehlikeli sularda yelken açıyorsunuz. Gelecekte hangi dosyaları kullanabileceğinizi kim bilebilir, - dosyaları unuttunuz.
B.Tanner,

1
@ B.Tanner, evet. Bir anlamda sorun, komut satırı argümanlarının sadece düz dizgeler olmasıdır. Sistem bugün tasarlandıysa, içinde daha fazla yapı olabilir, böylece yürütülen program bir argümanın bir seçenek bayrağı olup olmadığını öğrenebilirdi. Dosya adlarının çok gevşek yapısından kaynaklanan başka problemler de var. Bu konuda sakinler tarafından çok kapsamlı bir yazı var , ancak okudumun acıtmayacağı konusunda uyarmalıyım. (Ya ayrıntıdan ya da neyin yanlış gidebileceğinin tamamen korkunçluğundan.)
ilkkachu

3
Karşı koyamam, bana sattın, şimdi okumaya başladım, zamanın hatıraları ile, bir sürü dosya adının sonunda bir satır başı karakteri alabildim. Ayrıca bir bash betiği olarak da çalışabilen bir Windows toplu iş dosyası oluşturun ... Bunun geldiğini görmedim!)
B.Tanner

17

Sadece ne bir kenara kabuk davranışı, diyelim odağını bırakmak rmve lskendileri ile başa çıkabilirim. En az bir vaka lsneyi gösterecek rmözel dizinleri - kaldıramazsınız dizin izinleri ve diğer içerir .ve ...

Klasör izinleri

rmBir dizindeki bir işlemdir, çünkü bir dosyayı kaldırarak, dizin içeriğini değiştirirsiniz (ya da başka bir deyişle dizin girdilerinin listesi, çünkü dosya dizini dosya isimleri ve inode'lardan başka bir şey değildir ). Bu, bir dizinde yazma iznine ihtiyacınız olduğu anlamına gelir. Dosyanın sahibi olsanız bile , dizin izinleri olmadan dosyaları kaldıramazsınız. Bunun tersi de geçerlidir : rmDizin sahibiyseniz, başkalarının sahip olabileceği dosyaları kaldırabilirsiniz.

Sen çok iyi okumak ve örneğin, sadece ince içindeki dizin ve görünümü içeriğini çapraz izin verecek olan bir dizinin yürütme izinleri olabilir Yani ls /bin/echo, ancak edemez rm /bin/echohesabının sahibi olmadıkça /bin veya ile ayrıcalıkları yükseltmek sudo.

Ve her yerde bu gibi vakaları göreceksiniz. İşte böyle bir durum: https://superuser.com/a/331124/418028


Özel dizinler '.' ve '..'

Diğer bir özel durum .ve ..dizinler. İsterseniz ls .veya size ls ..mutlu bir şekilde içeriği gösterir, ancak rmizin verilmemektedir:

$ rm -rf .
rm: refusing to remove '.' or '..' directory: skipping '.'

15

Eğer yazarsanız ls *ve sonra rm *, lsgösterilenden daha fazla dosyayı kaldırırsınız - bunların sonu lsile başlangıcı arasındaki küçük zaman aralığında yaratılmış olabilirler rm.


1
Bu /tmp, birçok uygulamanın geçici dosyalar oluşturabileceği muhtemel bir durumdur , bu nedenle her iki komutta da her zaman bir olasılık vardır *. Ancak, bazı uygulamalar da unlink()dosya tanıtıcısını açık tutarken onları adlandırarak dosyaları adsız kılar , bu nedenle gösterebilir, ls *ancak rm *yakalayamayabilir.
Sergiy Kolodyazhnyy

1
@OrangeDog Noktayı kaçırıyorsunuz. Yarış koşullarından bahsediyoruz
Sergiy Kolodyazhnyy

1
@OrangeDog Şu an telefonda olduğum için bunu doğrulamam gerekecek, ancak ara sıra, *neyin lsgösterileceği ile neyin rmçalıştığı arasındaki fark var olsa da , çünkü dizin içeriğinin listesi arasında bir değişiklik oldu.
Sergiy Kolodyazhnyy

1
Yalnızca bir komut verseniz bile, argümanları genişletmek ve sonra bunları silmek arasında bir yarış koşulu vardır.
Monica'ya Zarar Vermeyi Durdurun

1
@OrangeDog Buna katılıyorum. Joker karakter genişletme varolan dosya adları üzerinde çalıştığı için, evet, joker karakterin genişletilmesiyle kabuk arasında bir komut koşulu vardır ve onu işleyen bir komut vardır, böylece ls *gerçekte zaten giden dosya adını gösterebilir.
Sergiy Kolodyazhnyy

9

ls *ve rm *globun genişletilmesinden sorumlu değillerdir - kabuğa komuta geçmeden önce bu yapılır.

Bu , genişletilmiş dosya listesi ile herhangi bir komutu kullanabileceğiniz anlamına gelir - bu yüzden mümkün olan en az şeyi yapan bir şey kullanırdım.

Yani bunu yapmanın daha iyi bir yolu (ya da en azından başka bir şekilde) orta adamı atlamak.

echo *tam olarak emrinize ne geçileceğini size gösterecektir rm.


2
Teşekkür ederim, bu senaryoda ls yerine yankı kullanma fikrini seviyorum.
B.Tanner,

3
Veya printf "%s\n" *boşluk içeren dosya isimlerinde net bir görünüm elde etmek için. (Veya %qyeni satırlar ve kontrol karakterleriyle de başa çıkmak yerine, çirkin çıktı pahasına).
ilkkachu

4

Peki ya:

$ mkdir what
$ cd what
$ mkdir -p huh/uhm ./-r
$ ls *
uhm
$ rm *
$ ls
-r
$ ls -R
.:
-r

./-r:

Temel olarak joker karakterlerle başlayan -(veya elle başlayan -ama biraz hile gibi görünen şeyler) genişleyen joker karakterler , lsve tarafından farklı yorumlanabilir rm.


4

Orada olan nerede ne kenar durumlarda lsgösterileri ne değildir rmkaldırır. Oldukça aşırı, ama neyse ki iyi huylu biri, aktardığınız argüman bir dizine sembolik bir bağsa: lssize bağlanan dizindeki tüm dosyaları gösterecek rm, orijinal dizini ve içeriğini dokunmadan bırakarak sembolik bağlantıyı kaldıracaktır:

% ln -s $HOME some_link
% ls some_link    # Will display directory contents  
bin    lib    Desktop ...
% rm some_link
% ls $HOME
bin    lib    Desktop ...

1
Huh. ln -s $HOME some_link; ls some_linkçıktılar some_link@benim için, ama lstakma isimler var ls -F. Anlaşılan, -Fbağlantıyı gösterme yerine bağlantı gösterme davranışını değiştiriyor. Bunu beklemiyordum.
marcelm

Aslında! Ayrıca ls -lörneğin bağlantıyı hedef alır, hedefi değil ... bağlantıyı denetlemenin yolları olması gerekir.
alexis

1
Sorusuna seçenekleri ekleme çok fazla açılır possibilities-- cevabım değiştirilmemiş davranışı hakkında ise lsve rm.
alexis

Derseniz ls some_link/,  ls -H some_linkya ls -L some_link, bu ancak bağlantılı dizin eklemek bile listeler -Fveya -l. Tersine (sıralama), -diçeriğinden ziyade bir dizine bakmayı söylüyor; karşılaştır ls -l /tmpve ls -ld /tmp.
G-Man

Elbette, davranışını değiştiren bayraklar ekleyebilirsiniz ls. Temelde, farklı bayraklarla davranışların numaralandırılmasının neden bu soruna zahmete değmediğini gösteriliyor ...
alexis

4

Yalnızca yaparsanız lsyerine ls -a, evet rmsen ile görmedim gizli dosyaları kaldırabilirsiniz lsolmadan -a.

Örnek :

Göre :

dir_test
├── .test
└── test2

ls dir_test : sadece test2 gösterilecek

ls -A dir_test : test2 + .test gösterecektir

rm -r dir_test : tümünü kaldıracak (.test + test2)

Umarım bu size yardımcı olur.


Bir örnek verebilir misiniz? Çünkü normalde rm *dotfiles silinmez. Olursa, ls *onlara da gösterecektir.
marcelm

Hayır, ls *gizli dosyaları gösterme.
DevHugo

Ama evet biraz karışık, bazı örnekler ekledim.
DevHugo

1
ls -alisteler ., .., .testve test2. Sen kullanımı için örnek değiştirmek isteyebilirsiniz ls -A, hangi liste her şeyi hariç . ve ..(yani sadece .testve test2).
G-Man

3

Zaten çok iyi cevaplar var, fakat daha derin bir içgörü eklemek istiyorum.

Kendinize şu soruyu sorun: geçirilir kaç parametreleri ls, sen yazarsan

ls *

...? Genişletilebilecek dosyalar varsa , lskomutun *as parametresini almadığını unutmayın *. Bunun yerine, kabuk ilk önce komutu çalıştırmadan önce taşınma işlemini gerçekleştirir, bu nedenle lskomut aslında taşınma ile eşleşen dosyalar kadar çok parametre alır. Kürelemeyi bastırmak için parametreyi alıntılayın.

Bu, herhangi bir komut için de geçerlidir: echo *vs echo '*'.

Bir komut dosyası var, countparams.shefekti test etmek için onu arayın . Kaç tane parametrenin geçtiğini gösterir ve bunları listeler.

#!/bin/bash
echo "This script was given $# parameters."
arr=( "$@" )
for ((i=0;i<$#;i++)); do
        echo "Parameter $((i+1)): ${arr[$i]}"
done

Çalıştırılabilir ve çalıştırın ./countparams.sh *. Çıktısından öğrenin!


1

Glob, aynı şekilde iki kere genişleyecektir eğer dizin içerikleri bu iki farklı zamanlarda aynıdır.


Gerçekten neyin kaldırılacağını kontrol etmek istiyorsanız, kullanın rm -i *.txt. Çıkarmadan önce (denemeye) önce her dosya için ayrı ayrı bilgi ister.

Bunun yarış koşullarına karşı güvenli olduğu garantilidir:
        ls *.txt/ yeni bir dosya oluşturulur / rm *.txt
çünkü her dosya için sizden kaldırma işlemini yapan aynı program tarafından istenir.


Bu normal kullanım için çok zahmetlidir ve takma eğer rmetmek rm -i, kendinizi kullanarak bulacaksınız \rmya rm -foldukça sık. Ancak en azından yarış koşullarına bir çözüm bulunduğundan bahsetmeye değer. (GNU dışı sistemler için bile taşınabilir: POSIX seçeneği rm(1)belirtir-i .)

Başka bir seçenek bir bash dizisi olacaktır:, to_remove=(*.txt)ardından kullanıcıdan onaylamasını isteyin (belki de yaptıktan sonra ls -ld -- "${to_remove[@]}"), sonra rm -- "${to_remove[@]}". Dolayısıyla, genişleme genişlemesi yalnızca bir kez yapılır ve liste sözlü olarak iletilir rm.

Pratik olarak kullanılabilen bir diğer seçenek ise , 4'ten fazla öğenin kaldırılıp kaldırılmayacağını isteyen GNU rm -I( kılavuz sayfası ). (Ama size toplamı göstermiyor, sadece toplamı.) alias rm='rm -I'Masaüstümde kullanıyorum.

Çok fazla uyuşan yarı yazılı bir desenle yağ parmaklarınızın geri dönüşüne karşı güzel bir koruma sağlar. Ancak, lsilkini kullanmak genellikle sahip olduğunuz bir dizinde veya tek kullanıcılı bir sistemde ve eşzamansız olarak yeni dosyalar oluşturabilecek arka plan işlemleri olmadığında iyidir. Yağ parmaklarına karşı korunmak için rm -rf /foo/bar/bazsoldan sağa doğru yazmayın . rm -rf /özel kasalı, ama rm -rf /usrdeğil! Parçayı dışarıda bırakın -rfveya ile başlayın lsve yalnızca rm -rfyolu yazdıktan sonra parçayı ekleyin .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.