Czy ktoś ma skrypt powłoki szablonów do robienia czegoś z ls
listą nazw katalogów i do przechodzenia między nimi i robienia czegoś?
Planuję zrobić, ls -1d */
aby uzyskać listę nazw katalogów.
źródło
Czy ktoś ma skrypt powłoki szablonów do robienia czegoś z ls
listą nazw katalogów i do przechodzenia między nimi i robienia czegoś?
Planuję zrobić, ls -1d */
aby uzyskać listę nazw katalogów.
Edytowano, aby nie używać ls tam, gdzie zrobiłby glob, jak sugerowali @ shawn-j-goff i inni.
Wystarczy użyć for..do..done
pętli:
for f in *; do
echo "File -> $f"
done
Można wymienić *
z *.txt
lub dowolny inny glob, która zwraca listę (plików, katalogów lub cokolwiek na ten temat), polecenie, które generuje listę, na przykład $(cat filelist.txt)
, czy rzeczywiście należy wymienić go na liście.
W do
pętli po prostu odwołujesz się do zmiennej pętli z prefiksem znaku dolara (tak $f
w powyższym przykładzie). Możesz echo
to zrobić lub zrobić cokolwiek innego, co chcesz.
Na przykład, aby zmienić nazwę wszystkich .xml
plików w bieżącym katalogu na .txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
Lub jeszcze lepiej, jeśli używasz Bash, możesz użyć rozszerzeń parametrów Bash zamiast odradzania podpowłoki:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
pętli i typową pułapkę podczas próby przetworzenia wynikuls
. @ DanielA.White, to może rozważyć unaccepting tę odpowiedź, jeśli nie był pomocny (lub potencjalnie mylące), ponieważ jak powiedziałeś, jesteś działając w katalogach. Odpowiedź Shawna J. Goffa powinna zapewnić bardziej niezawodne i działające rozwiązanie twojego problemu.ls
danych wyjściowych , nie powinieneś czytać danych wyjściowych wfor
pętli , powinieneś użyć$()
zamiast `` i Użyj więcej cytatów ™ . Jestem pewien, że @CoverosGene miał dobre intencje, ale to po prostu okropne.ls
jestls -1 | while read line; do stuff; done
. Przynajmniej ten nie złamie się dla białych znaków.mv -v
tobą nie potrzebujeszecho "moved $x -> $t"
Korzystanie z danych wyjściowych w
ls
celu uzyskania nazw plików jest złym pomysłem . Może to prowadzić do nieprawidłowego działania, a nawet niebezpiecznych skryptów. To dlatego, że nazwa pliku może zawierać dowolny znak oprócz/
inull
charakter, als
nie korzysta z żadnego z tych znaków jako ograniczniki, więc jeśli nazwa pliku zawiera spację lub znak nowej linii, to będzie otrzymać nieoczekiwane rezultaty.Istnieją dwa bardzo dobre sposoby iteracji plików. Tutaj zwykłem
echo
demonstrować robienie czegoś z nazwą pliku; możesz jednak użyć wszystkiego.Pierwszym z nich jest użycie natywnych funkcji globowania powłoki.
Powłoka rozwija się
*/
w osobne argumentyfor
odczytywane przez pętlę; nawet jeśli w nazwie pliku znajduje się spacja, znak nowej linii lub jakikolwiek inny dziwny znak,for
każda pełna nazwa będzie postrzegana jako jednostka atomowa; w żaden sposób nie analizuje listy.Jeśli chcesz przechodzić rekurencyjnie do podkatalogów, nie będzie to możliwe, chyba że twoja powłoka ma jakieś rozszerzone funkcje globowania (takie jak
bash
sglobstar
. w różnych systemach, następną opcją jest użyciefind
.Tutaj
find
polecenie wywołaecho
i przekaże mu argument nazwy pliku. Robi to raz dla każdego znalezionego pliku. Podobnie jak w poprzednim przykładzie, nie ma parsowania listy nazw plików; zamiast tego nazwa pliku jest wysyłana całkowicie jako argument.Składnia
-exec
argumentu wygląda trochę zabawnie.find
pobiera pierwszy argument za-exec
i traktuje go jako program do uruchomienia, a każdy kolejny argument przyjmuje jako argument do przekazania do tego programu. Są dwa specjalne argumenty, które-exec
należy zobaczyć. Pierwszy to{}
; ten argument zostaje zastąpiony nazwą pliku, którąfind
generują poprzednie części . Drugi to;
, który informujefind
, że jest to koniec listy argumentów przekazywanych do programu;find
potrzebuje tego, ponieważ możesz kontynuować z większą liczbą argumentów, które są przeznaczonefind
i nie są przeznaczone dla wykonywanego programu. Powodem\
jest to, że powłoka również traktuje;
szczególnie - reprezentuje koniec polecenia, więc musimy uciec od niego, aby powłoka podała go jako argumentfind
zamiast konsumować go dla siebie; innym sposobem, aby powłoka nie traktowała go specjalnie, jest umieszczenie go w cudzysłowach:';'
działa tak dobrze, jak\;
w tym celu.źródło
find
. Istnieje magia, którą można zrobić, a nawet postrzegane ograniczenia-exec
można obejść.-print0
Opcją jest także cenne dla użycia zxargs
.W przypadku plików ze spacjami musisz podać zmienną:
lub możesz zmienić zmienną środowiskową separatora pól wejściowych (IFS):
Wreszcie, w zależności od tego, co robisz, możesz nawet nie potrzebować ls:
źródło
\n
jest niewystarczające. Nigdy nie jest dobrym pomysłem zalecanie analizy wynikuls
.Jeśli masz zainstalowany GNU Parallel http://www.gnu.org/software/parallel/, możesz to zrobić:
Aby zmienić nazwę wszystkich plików .txt na .xml:
Obejrzyj wideo wprowadzające do GNU Parallel, aby dowiedzieć się więcej: http://www.youtube.com/watch?v=OpaiGYxkSuQ
źródło
Aby dodać do odpowiedzi CoverosGene, oto sposób na podanie tylko nazw katalogów:
źródło
Dlaczego nie ustawić IFS na nowy wiersz, a następnie przechwycić dane wyjściowe
ls
w tablicy? Ustawienie IFS na nowy wiersz powinno rozwiązać problemy ze śmiesznymi znakami w nazwach plików; używaniels
może być przyjemne, ponieważ ma wbudowaną funkcję sortowania.(Podczas testowania miałem problem z ustawieniem IFS na,
\n
ale ustawienie na backspace nowej linii działa, jak sugerowano gdzie indziej tutaj):Np. (Zakładając, że
ls
przekazano pożądany wzorzec wyszukiwania$1
):Jest to szczególnie przydatne w systemie OS X, np. Aby przechwycić listę plików posortowanych według daty utworzenia (od najstarszej do najnowszej),
ls
polecenie tols -t -U -r
.źródło
\n
jest niewystarczające. Jedyne prawidłowe rozwiązania używają pętli for z rozszerzaniem nazw ścieżek lubfind
.Tak to robię, ale są prawdopodobnie bardziej wydajne sposoby.
źródło
ls | while read i; do echo filename: $i; done