Mam skrypt, który przeszukuje wszystkie pliki w wielu podfolderach i archiwach do tar. Mój skrypt jest
for FILE in `find . -type f -name '*.*'`
do
if [[ ! -f archive.tar ]]; then
tar -cpf archive.tar $FILE
else
tar -upf archive.tar $FILE
fi
done
Polecenie find daje mi następujące dane wyjściowe
find . -type f -iname '*.*'
./F1/F1-2013-03-19 160413.csv
./F1/F1-2013-03-19 164411.csv
./F1-FAILED/F2/F1-2013-03-19 154412.csv
./F1-FAILED/F3/F1-2011-10-02 212910.csv
./F1-ARCHIVE/F1-2012-06-30 004408.csv
./F1-ARCHIVE/F1-2012-05-08 190408.csv
Ale zmienna FILE przechowuje tylko pierwszą część ścieżki ./F1/F1-2013-03-19, a następnie kolejną część 160413.csv .
Próbowałem użyć read
pętli while,
while read `find . -type f -iname '*.*'`; do ls $REPLY; done
ale pojawia się następujący błąd
bash: read: `./F1/F1-2013-03-19': not a valid identifier
Czy ktoś może zaproponować alternatywny sposób?
Aktualizacja
Zgodnie z sugestiami w poniższych odpowiedziach zaktualizowałem skrypty
#!/bin/bash
INPUT_DIR=/usr/local/F1
cd $INPUT_DIR
for FILE in "$(find . -type f -iname '*.*')"
do
archive=archive.tar
if [ -f $archive ]; then
tar uvf $archive "$FILE"
else
tar -cvf $archive "$FILE"
fi
done
Otrzymałem wynik
./test.sh
tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
IFS=$'\n'
przed pętlą `for, aby parsować każdą linięOdpowiedzi:
Używanie
for
zfind
jest tutaj niewłaściwym podejściem, patrz na przykład ten opis puszki otwieranych przez ciebie robaków.Zalecanym sposobem jest użycie
find
,while
iread
jak opisano tutaj . Poniżej znajduje się przykład, który powinien działać dla Ciebie:W ten sposób rozgraniczasz nazwy plików
\0
znakami null ( ), co oznacza, że zmiana przestrzeni i innych znaków specjalnych nie spowoduje problemów.Aby zaktualizować archiwum z
find
lokalizowanymi plikami , możesz przekazać jego dane wyjściowe bezpośrednio dotar
:Pamiętaj, że nie musisz rozróżniać, czy archiwum istnieje, czy nie,
tar
obsłuży je rozsądnie. Zwróć też uwagę na użycie-printf
tutaj, aby uniknąć włączenia./
bitu do archiwum.źródło
./
jako smoły../.tar tar: ./archive.tar: file is the archive; not dumped
if [[ "$FILE" == "./" ]]; then
continue
./
dzięki-printf
zaktualizowanej odpowiedzi. Jednak nie powinno to mieć znaczenia, czy jest dołączone, czy nie, ponieważ odnosi się tylko do bieżącego katalogu. Podałem również alternatywnąfind/tar
kombinację, której możesz chcieć użyć.sort
wyników przed iteracją, potrzebujeszsort -z
separatora zerowego.Spróbuj zacytować
for
pętlę w ten sposób:Bez cudzysłowów bash nie radzi sobie dobrze ze spacjami i znakami nowej linii (
\n
) ...Spróbuj także ustawienia
źródło
comm
do porównania posortowanych list plików, a nazwy plików zawierały spacje, pomimo cytowania zmiennych nie działało. Potem zobaczyłem, że cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html i rozwiązanie ustawienia $ IFS z IFS = $ (echo -en "\ n \ b") zadziałało dla mnie.To działa i jest prostsze:
Podziękowania dla Rupy ( https://github.com/rupa/z ) za tę odpowiedź.
źródło
Oprócz poprawnego cytowania możesz powiedzieć,
find
aby użyć separatora NULL, a następnie odczytać i przetworzyć wyniki wwhile
pętliTo powinno obsłużyć wszystkie nazwy plików, które są zgodne z POSIX - patrz
man find
źródło
źródło
Zrobiłem coś takiego, aby znaleźć pliki, które mogą zawierać spacje.
Działa jak urok :)
źródło
Większość odpowiedzi tutaj się nie zgadza, jeśli w nazwie pliku znajduje się znak nowej linii. Używam bashu ponad 15 lat, ale tylko interaktywnie.
W Python możesz nam os.walk (): http://docs.python.org/2/library/os.html#os.walk
I moduł tarfile: http://docs.python.org/2/library/tarfile.html#tar-examples
źródło
Myślę, że lepiej będzie
find
skorzystać z opcji -exec.Znajdź następnie wykonuje polecenie za pomocą wywołania systemowego, aby zachować spacje i znaki nowej linii (raczej potok, który wymagałby cytowania znaków specjalnych). Zauważ, że „tar -c” działa niezależnie od tego, czy archiwum już istnieje, i że (przynajmniej z bash) ani {}, ani + nie muszą być cytowane.
źródło
Jak sugeruje minerz029, musisz zacytować rozszerzenie
find
polecenia. Musisz także zacytować wszystkie podstawienia$FILE
w swojej pętli.Zauważ, że
$()
składnia powinna być preferowana przed użyciem backicks; patrz ten U L pytanie . Usunąłem również[[
słowo kluczowe i zastąpiłem je[
poleceniem, ponieważ jest to POSIX.źródło
[[
i[
wydaje się, że[[
jest nowszy i obsługuje więcej funkcji, takich jak globowanie i dopasowywanie wyrażeń regularnych.[[
jest tylko wbash
nie,sh
[[
mówiąc o wspieraniu globowania. Według wiki Grega wewnątrz globusa nie ma miejsca[[
.[ "ab" == a? ] && echo "true"
więc[[ "ab" == a? ]] && echo "true"
a*
oznacza „po którym następuje dowolna liczba znaków”, a nie „wszystkie pliki, których nazwy zaczynają sięa
i mają później dowolną liczbę znaków”. Spróbuj[ ab = a* ] && echo true
kontra[[ ab == a* ]] && echo true
.[[
nadal robi wyrażenia regularne, podczas gdy[
nie robi. Musiał się pomylić