Próbuję skopiować kilka plików poniżej katalogu, a niektóre z nich mają spacje i cudzysłowy w swoich nazwach. Podczas próby ciągnięcia razem find
i za grep
pomocą xargs
tego pojawia się następujący błąd:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
Wszelkie sugestie dotyczące bardziej niezawodnego korzystania z xargs?
To jest na Mac OS X 10.5.3 (Leopard) z BSD xargs
.
--delimiter
opcję (-d
). Wypróbuj\n
jako separator, Zapobiega toxargs
rozdzielaniu wierszy ze spacjami na kilka słów / argumentów.Odpowiedzi:
Możesz połączyć to wszystko w jedno
find
polecenie:Będzie to obsługiwać nazwy plików i katalogów ze spacjami w nich. Możesz użyć,
-name
aby uzyskać wyniki z rozróżnianiem wielkości liter.Uwaga:
--
przekazana flagacp
uniemożliwia przetwarzanie plików zaczynających się od-
jako opcji.źródło
xargs
nie jest wymagany do rozwiązania opisywanego problemu,find
obsługuje go już-exec
+
interpunkcja.find . -print0 | grep --null 'FooBar' | xargs -0 ...
Nie wiem, czy
grep
obsługuje--null
, czy teżxargs
obsługuje-0
, na Leopardzie, ale na GNU wszystko jest dobre.źródło
grep -{z|Z}
oznacza „zachowuj się jak zgrep” (dekompresja), a nie zamierzone „drukowanie bajtu zerowego po każdej nazwie pliku”. Użyj,grep --null
aby osiągnąć to drugie.find . -name 'FooBar' -print0 | xargs -0 ...
?-name
lub-path
działa dobrze. OP określił użyciegrep
, prawdopodobnie dlatego, że chce filtrować listę przy użyciu wyrażeń regularnych.xargs -0
w połączeniu zfind -print0
. Drugi drukuje nazwy plików za pomocą terminatora NUL, a pierwszy odbiera pliki w ten sposób. Czemu? Nazwy plików w systemie Unix mogą zawierać znaki nowego wiersza. Ale nie mogą zawierać znaków NUL.Najłatwiejszym sposobem na zrobienie tego, co chce oryginalny plakat, jest zmiana separatora z dowolnej białej spacji na znak końca linii, taki jak ten:
źródło
sed -e 's_\(.*\)_"\1"_g'
celu wymuszenia cudzysłowu wokół nazwy plikuxargs
.xargs: illegal option -- d
Jest to bardziej wydajne, ponieważ nie uruchamia wielokrotnie „cp”:
źródło
Natrafiłem na ten sam problem. Oto jak to rozwiązałem:
Kiedyś
sed
zastępowałem każdy wiersz wejścia tą samą linią, ale otoczony podwójnymi cudzysłowami. Ze strony podręcznikased
„ ... Znak ampersand (` `& '') występujący w zastępstwie jest zastępowany ciągiem pasującym do RE ... ” - w tym przypadku.*
cała linia.To rozwiązuje
xargs: unterminated quote
błąd.źródło
sed s/.*/\"&\"/
, żeby działał."
in - chyba że sed również cytuje cytaty?sed
jest genialne i na razie poprawne rozwiązanie bez przepisywania problemu!Ta metoda działa w systemie Mac OS X 10.7.5 (Lion):
Przetestowałem również dokładną składnię, którą opublikowałeś. Działa to również dobrze w wersji 10.7.5.
źródło
-I
sugeruje-L 1
(tak mówi instrukcja), co oznacza, że polecenie cp jest uruchamiane raz na plik = v wolne.find ... -print0
ixargs -0
pracować wokół „xargs” domyślnie są specjalne ”. Po drugie, zwykle'{}'
nie używaj{}
poleceń przekazywanych do xargs, aby chronić przed spacjami i znakami specjalnymi.Po prostu nie używaj
xargs
. Jest to fajny program, ale nie pasuje dofind
nietrudnych przypadków.Oto przenośne (POSIX) rozwiązanie, to znaczy taki, który nie wymaga
find
,xargs
lubcp
GNU konkretnych rozszerzeń:Zwróć uwagę na zakończenie
+
zamiast bardziej zwykłego;
.To rozwiązanie:
poprawnie obsługuje pliki i katalogi z osadzonymi spacjami, znakami nowej linii lub dowolnymi egzotycznymi znakami.
działa na każdym systemie Unix i Linux, nawet tym, który nie udostępnia zestawu narzędzi GNU.
nie używa
xargs
ładnego i użytecznego programu, ale wymaga zbyt wiele poprawek i niestandardowych funkcji, aby poprawnie obsługiwaćfind
dane wyjściowe.jest również bardziej wydajny ( szybszy odczyt ) niż przyjęte i większość, jeśli nie wszystkie inne odpowiedzi.
Zauważ też, że pomimo tego, co podano w niektórych innych odpowiedziach lub komentarzach, cytowanie
{}
jest bezużyteczne (chyba że używasz egzotycznejfish
powłoki).źródło
find
może robić to, coxargs
robi bez żadnych kosztów ogólnych.Sprawdź użycie opcji wiersza polecenia --null dla xargs z opcją -print0 w find.
źródło
Dla tych, którzy polegają na poleceniach innych niż find, np .
ls
:źródło
-I
sugeruje-L 1
Uważam, że będzie to działało niezawodnie dla każdego znaku, z wyjątkiem przesyłu wiersza (i podejrzewam, że jeśli masz przesuwanie wiersza w nazwach plików, to masz gorsze problemy niż to). Nie wymaga GNU findutils, tylko Perl, więc powinien działać prawie wszędzie.
źródło
mkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
|perl -lne 'print quotemeta'
jest dokładnie tym, czego szukałem. Inne posty tutaj mi nie pomogły, ponieważ zamiastfind
musiałemgrep -rl
znacznie zmniejszyć liczbę plików PHP do tylko zainfekowanych złośliwym oprogramowaniem.Przekonałem się, że następująca składnia działa dla mnie dobrze.
W tym przykładzie szukam największych 200 plików powyżej 1 000 000 bajtów w systemie plików zamontowanym w „/ usr / pcapps”.
W linijce Perla między „find” a „xargs” znaki ucieczki / cytowania są puste, więc „xargs” przekazuje dowolną nazwę pliku z osadzonymi spacjami do „ls” jako pojedynczy argument.
źródło
Wyzwanie ramowe - pytasz, jak używać xargs. Odpowiedź brzmi: nie używasz xargs, ponieważ go nie potrzebujesz.
Komentarz
user80168
opisuje sposób to zrobić bezpośrednio z CP, bez wywoływania cp dla każdego pliku:Działa to, ponieważ:
cp -t
flaga pozwala podać katalog docelowy w pobliżu początkucp
, a nie pod koniec. Odman cp
:--
Flaga mówicp
interpretować wszystko po jako nazwy pliku, a nie flagi, więc pliki rozpoczynające się-
lub--
nie mylićcp
; nadal jest to potrzebne, ponieważ znaki-
/--
są interpretowane przezcp
, podczas gdy inne znaki specjalne są interpretowane przez powłokę.find -exec command {} +
Wariant zasadniczo działa tak samo jak xargs. Odman find
:Używając tego bezpośrednio w funkcji wyszukiwania, pozwala to uniknąć potrzeby wywoływania potoku lub powłoki, dzięki czemu nie trzeba się martwić o paskudne znaki w nazwach plików.
źródło
Należy pamiętać, że większość opcji omówionych w innych odpowiedziach nie jest standardem na platformach, które nie używają narzędzi GNU (na przykład Solaris, AIX, HP-UX). Zobacz specyfikację POSIX dla „standardowych” zachowań xargs.
Uważam również, że zachowanie xargs, w którym uruchamia polecenie co najmniej raz, nawet bez danych wejściowych, jest uciążliwe.
Napisałem własną prywatną wersję xargs (xargl), aby poradzić sobie z problemami spacji w nazwach (oddzielne są tylko nowe wiersze - chociaż kombinacja „znajdź ... -print0” i „xargs -0” jest całkiem fajna, biorąc pod uwagę, że nazwy plików nie mogą zawierają znaki ASCII NUL „\ 0.” Mój xargl nie jest tak kompletny, jak by go warto było opublikować - zwłaszcza, że GNU ma udogodnienia, które są co najmniej tak dobre.
źródło
find
nie potrzebujexargs
(a było to prawdą już 11 lat temu).Dzięki Bash (nie POSIX) możesz użyć podstawienia procesu, aby uzyskać bieżący wiersz w zmiennej. Umożliwia to stosowanie cudzysłowów do znaków specjalnych:
źródło
Dla mnie próbowałem zrobić coś nieco innego. Chciałem skopiować moje pliki .txt do mojego folderu tmp. Nazwy plików .txt zawierają spacje i znaki apostrofów. To działało na moim Macu.
źródło
Jeśli find a xarg wersje na komputerze nie obsługuje
-print0
i-0
przełączniki (na przykład AIX znaleźć i xargs) Można użyć tego kodu strasznie patrząc:Tutaj sed zajmie się ucieczką w miejsca i cytatami dla xargs.
Testowane w systemie AIX 5.3
źródło
Stworzyłem mały przenośny skrypt otoki o nazwie „xargsL” wokół „xargs”, który rozwiązuje większość problemów.
W przeciwieństwie do xargs, xargsL akceptuje jedną ścieżkę w linii. Ścieżki mogą zawierać dowolny znak oprócz (oczywiście) nowej linii lub bajtów NUL.
Cytowanie na liście plików nie jest dozwolone ani obsługiwane - nazwy plików mogą zawierać wszelkiego rodzaju białe znaki, ukośniki odwrotne, znaki wsteczne, znaki wieloznaczne powłoki i tym podobne - xargsL przetworzy je jako znaki dosłowne, bez szkody.
Jako dodatkowa funkcja bonusowa, xargsL nie uruchomi polecenia raz, jeśli nie ma danych wejściowych!
Zwróć uwagę na różnicę:
Wszelkie argumenty podane xargsL zostaną przekazane do xargs.
Oto skrypt powłoki POSIX „xargsL”:
Umieść skrypt w jakimś katalogu w $ PATH i nie zapomnij
$ chmod +x xargsL
skrypt tam, aby był wykonywalny.
źródło
Wersja Perla bill_starr nie działa dobrze dla osadzonych znaków nowej linii (tylko kopiuje ze spacjami). Dla tych na np. Solaris, gdzie nie masz narzędzi GNU, bardziej kompletna wersja może być (używając sed) ...
dostosuj argumenty find i grep lub inne polecenia według potrzeb, ale sed naprawi osadzone znaki nowej linii / spacje / tabulatory.
źródło
W Solarisie użyłem nieco zmodyfikowanej odpowiedzi Billa Star :
Spowoduje to umieszczenie cudzysłowów wokół każdej linii. Nie użyłem opcji „-l”, chociaż prawdopodobnie to pomogłoby.
Lista plików, którą wybrałem, może mieć „-”, ale nie nowe wiersze. Nie użyłem pliku wyjściowego z żadnymi innymi poleceniami, ponieważ chcę sprawdzić, co zostało znalezione, zanim zacznę masowo je usuwać za pomocą xargs.
źródło
Trochę się z tym bawiłem, zacząłem zastanawiać się nad modyfikacją xargs i zdałem sobie sprawę, że dla tego rodzaju zastosowania, o którym tu mówimy, lepszym pomysłem jest prosta ponowna implementacja w Pythonie.
Po pierwsze, posiadanie ~ 80 linii kodu dla całej rzeczy oznacza, że łatwo jest dowiedzieć się, co się dzieje, a jeśli wymagane jest inne zachowanie, możesz po prostu włamać go do nowego skryptu w krótszym czasie niż potrzeba, aby uzyskać odpowiedź na coś takiego jak przepełnienie stosu.
Zobacz https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs i https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py .
Mając napisane yargs (i zainstalowany Python 3), możesz pisać:
wykonać kopiowanie 203 plików jednocześnie. (Tutaj 203 jest oczywiście symbolem zastępczym, a użycie dziwnej liczby, takiej jak 203, wyraźnie pokazuje, że liczba ta nie ma innego znaczenia).
Jeśli naprawdę chcesz czegoś szybciej i bez potrzeby używania Pythona, weź Zargs i Yargs jako prototypy i przepisz w C ++ lub C.
źródło
Może być konieczne grepowanie katalogu Foobar, takiego jak:
źródło
-i
jest przestarzały i-I
należy go użyć zamiast tego.Jeśli używasz Bash, możesz przekonwertować standardowe wyjście na tablicę wierszy poprzez
mapfile
:Korzyści to:
Możesz dołączyć inne argumenty do nazw plików. Dla
cp
, można również:jednak niektóre polecenia nie mają takiej funkcji.
Wady:
Cóż ... kto wie, czy Bash jest dostępny na OS X?
źródło