awk 'processing_script_here' my=file.txt
wydaje się zatrzymywać i czekać w nieskończoność ...
Co się tutaj dzieje i jak mam to zrobić?
awk 'processing_script_here' my=file.txt
wydaje się zatrzymywać i czekać w nieskończoność ...
Co się tutaj dzieje i jak mam to zrobić?
Odpowiedzi:
Jak mówi Chris , argumenty formularza variablename=anythingsą traktowane jako przypisanie zmiennej (wykonywane w momencie przetwarzania argumentów, w przeciwieństwie do (nowszych) -v var=value, które są wykonywane przed BEGINinstrukcjami) zamiast nazw plików wejściowych.
Może to być przydatne w takich przypadkach jak:
awk '{print $1}' FS=/ RS='\n' file1 FS='\n' RS= file2
Gdzie możesz określić inny FS/ RSna plik. Jest również powszechnie stosowany w:
awk '!file1_processed{a[$0]; next}; {...}' file1 file1_processed=1 file2
Która jest bezpieczniejszą wersją:
awk 'NR==FNR{a[$0]; next}; {...}' file1 file2
(co nie działa, jeśli file1jest puste)
Ale to przeszkadza, gdy masz pliki, których nazwa zawiera =znaki.
To tylko problem, gdy resztą pierwszego =jest poprawna awknazwa zmiennej.
To, co stanowi prawidłową nazwę zmiennej w, awkjest surowsze niż w sh.
POSIX wymaga czegoś takiego jak:
[_a-zA-Z][_a-zA-Z0-9]*
Tylko znaki z przenośnego zestawu znaków. Jednak /usr/xpg4/bin/awkSolaris 11 przynajmniej nie jest zgodny w tym względzie i dopuszcza wszelkie znaki alfabetyczne w ustawieniach regionalnych w nazwach zmiennych, nie tylko a-zA-Z.
Zatem argument taki jak x+y=foolub =barlub ./foo=barjest nadal traktowany jako nazwa pliku wejściowego, a nie przypisanie, ponieważ to, co pozostało z pierwszego, =nie jest prawidłową nazwą zmiennej. Argument taki Stéphane=Chazelas.txtmoże, ale nie musi, w zależności od awkimplementacji i ustawień regionalnych.
Dlatego w awk zaleca się stosowanie:
awk '...' ./*.txt
zamiast
awk '...' *.txt
na przykład, aby uniknąć problemu, jeśli nie możesz zagwarantować, że nazwa txtplików nie będzie zawierać =znaków.
Pamiętaj też, że taki argument -vfoo=bar.txtmoże być traktowany jako opcja, jeśli używasz:
awk -f file.awk -vfoo=bar.txt
(Dotyczy to również awk '{code}' -vfoo=bar.txtz awkod wersji BusyBox przed 1.28.0, patrz odpowiadający raport o błędzie ).
Ponownie, użycie ./*.txtdziała w ten sposób (użycie ./przedrostka pomaga również w wywołaniu pliku, -który inaczej awkrozumie się jako oznaczający standardowe wejście ).
Właśnie dlatego
#! /usr/bin/awk -f
sekstensy naprawdę nie działają. Podczas gdy var=valuete można obejść poprzez ustalenie tych ARGVwartości (dodać ./przedrostek) w BEGINoświadczeniu:
#! /usr/bin/awk -f
BEGIN {
for (i = 1; i < ARGC; i++)
if (ARGV[i] ~ /^[_[:alpha:]][_[:alnum:]]*=/)
ARGV[i] = "./" ARGV[i]
}
# rest of awk script
To nie pomoże w przypadku opcji, ponieważ są one widziane przez skrypt, awka nie przez niego awk.
Jednym z potencjalnych problemów kosmetycznych z użyciem tego ./prefiksu jest to, że się kończy FILENAME, ale zawsze możesz substr(FILENAME, 3)go rozebrać, jeśli nie chcesz.
Implementacja GNU awknaprawia wszystkie te problemy z jej -Eopcją.
Po tym -Egawk oczekuje tylko ścieżki awkskryptu (gdzie -wciąż oznacza stdin), a następnie tylko listy ścieżek do pliku wejściowego (i tam nawet nie -jest specjalnie traktowany).
Jest specjalnie zaprojektowany dla:
#! /usr/bin/gawk -E
shebangs, w których lista argumentów jest zawsze plikami wejściowymi (pamiętaj, że nadal możesz edytować tę ARGVlistę w BEGINinstrukcji).
Możesz także użyć go jako:
gawk -e '...awk code here...' -E /dev/null *.txt
Używamy -Ez pustym skryptem ( /dev/null), aby upewnić się, że *.txtpóźniej będą zawsze traktowane jako pliki wejściowe, nawet jeśli zawierają =znaki.
../foo, /path/to/fooi ścieżki, które są w innym kodowaniu) - w którym to przypadku substr(FILENAME,3)nie wystarczy, lub skrypt z jednym strzałem, w którym użytkownik w zasadzie zna nazwy plików - w takim przypadku prawdopodobnie nie powinien zawracać sobie głowy żadnym z nich, który zawiera =albo ;-)
./stanowiło to problem, ale może być niepożądane w pewnych warunkach, takich jak przypadki, w których nazwa pliku musi zostać dołączona do wyjścia, w którym to przypadku ./powinna być nadmiarowa i niepotrzebna, więc Muszę się go jakoś pozbyć. Oto co najmniej jeden przykład . Co do użytkownika, który wie, jakie są nazwy plików - cóż, w tym przypadku wiemy również, co to jest nazwa pliku, ale =wciąż przeszkadza w prawidłowym przetwarzaniu. Więc prowadzenie może -przeszkodzić.
./przedrostka, aby obejść tę awk(błędną) funkcję, ale potem uzyskasz wynik ./wyjściowy, który możesz chcieć usunąć. Zobacz, jak sprawdzić, czy pierwszy wiersz pliku zawiera określony ciąg? jako przykład.
./ale także globalny (ścieżka bezwzględna), /dzięki czemu awk interpretuje argument jako plik.
W większości wersji awk argumentami po uruchomieniu programu są:
x=yPonieważ twoja nazwa pliku jest interpretowana jako przypadek nr 2, awk wciąż czeka na coś do odczytania na stdin (ponieważ nie rozpoznaje, że nazwa pliku została przekazana).
Przenośne zachowanie to jest udokumentowane w POSIX :
Można zmieszać jeden z dwóch poniższych typów argumentów:
- plik: ścieżka do pliku zawierającego dane wejściowe do odczytu, która jest dopasowywana do zestawu wzorców w programie. Jeżeli nie podano żadnych argumentów pliku lub jeśli argumentem pliku jest „-”, należy użyć standardowego wejścia.
- przypisanie: operand rozpoczynający się znakiem podkreślenia lub alfabetem z przenośnego zestawu znaków (patrz tabela w tomie Definicje podstawowe IEEE Std 1003.1-2001, sekcja 6.1, Przenośny zestaw znaków), po którym następuje sekwencja podkreśleń, cyfr, natomiast alfabet z przenośnego zestawu znaków, po którym następuje znak „=”, określa raczej przypisanie zmiennej niż nazwę ścieżki.
Jako taki, przenośnie, masz kilka opcji (# 1 jest prawdopodobnie najmniej inwazyjny):
awk ... ./my=file, która omija to, ponieważ .nie jest „znakiem podkreślenia lub alfabetu z przenośnego zestawu znaków”.awk ... < my=file. Nie działa to jednak dobrze z wieloma plikami.ln my=file my_file, a następnie użyć my_filejak zwykle. Kopiowanie nie zostanie wykonane, a oba pliki zostaną poparte tymi samymi danymi i metadanymi i-węzłów. Po użyciu można bezpiecznie usunąć utworzone łącze, ponieważ liczba odwołań do i-węzła nadal będzie większa niż 0../my=file działa? % awk 'processing_script_here' ./my=file.txt awk: fatal: cannot open file ./my=file.txt' for reading (No such file or directory). Powinno być przenośne, ponieważ ./mynie jest prawidłową nazwą zmiennej, więc nie powinno być analizowane w ten sposób.
=jest poprzedzony znakiem podkreślenia lub alfabetem z przenośnego zestawu znaków (patrz tabela w tomie Definicje podstawowe IEEE Std 1003.1-2001, sekcja 6.1, Przenośny zestaw znaków), po którym następuje sekwencja znaków podkreślenia, cyfr i alfabetu z przenośnego zestawu znaków . więc ścieżka do pliku, taka jak ++foo=bar.txtlub =foolub, ./foo=barwszystko jest w porządku jako taka .lub +nie jest [_a-zA-Z].
./my=filezostaną przekazane dosłownie.
awk '{print $1,$2}' /etc/passwd. Chodzi o to, że otwarcie pliku przez powłokę w przeciwieństwie do awk nie ma znaczenia, czy sprawia, że jest on widoczny, czy nie. W rzeczywistości awk '{exit}' < /etc/passwdmożna oczekiwać awkod końca pierwszego rekordu, exitaby upewnić się, że pozostawi on pozycję w obrębie standardowego wejścia. POSIX tego wymaga. /usr/xpg4/bin/awkrobi to na Solarisie, ale ani gawknie mawkwydaje się tego robić na GNU / Linux.
awkten sposób.
Aby zacytować dokumentację gawk (uwaga dodana):
Wszelkie dodatkowe argumenty w wierszu poleceń są zwykle traktowane jako pliki wejściowe do przetworzenia w określonej kolejności. Jednak argument, który ma postać var = wartość, przypisuje wartość do zmiennej var - w ogóle nie określa pliku.
Dlaczego polecenie zatrzymuje się i czeka? Ponieważ w formularzu awk 'processing_script_here' my=file.txt nie ma pliku określonego przez powyższą definicję - my=file.txtjest interpretowany jako przypisanie zmiennej, a jeśli nie ma zdefiniowanego pliku awk, odczyta stdin (oczywiste z stracektórego wynika, że awk w takiej komendzie czeka na read(0,'...)syscall.
Jest to również udokumentowane w specyfikacji awk POSIX , patrz sekcja OPERANDS i część przypisań )
Przypisanie zmiennych jest widoczne, awk '{print foo}' foo=bar /etc/passwdponieważ wartość foojest drukowana dla każdej linii w / etc / passwd. Podanie ./foo=barlub pełna ścieżka jednak działa.
Zauważ, że działa straceon awk '1' foo=barjak sprawdzanie z cat foo=barpokazuje, że jest to specyficzny problem awk i execve nie pokazuje nazwę pliku jako argument przekazany, więc pociski nie mają nic wspólnego z przypisań zmiennych env w tej sprawie.
Dodatkowo należy pamiętać, że awk '...script...' foo=barnie spowoduje to tworzenia zmiennych środowiskowych przez powłokę, ponieważ przypisania zmiennych środowiskowych powinny poprzedzać polecenie, aby zadziałały. Patrz Zasady gramatyki powłoki POSIX , punkt nr 7. Dodatkowo można to sprawdzić za pomocąawk '{print ENVIRON["foo"]}' foo=bar /etc/passwd