Neden dosya adı = içeriyorsa awk durur ve bekler ve bunun üzerinde nasıl çalışılır?


Yanıtlar:


19

As Chris diyor , formun argümanlar variablename=anything((daha yeni) karşıt olarak argümanlar işlenir anda gerçekleştirilmesi değişken atama olarak kabul edilir -v var=valueönce yapılır olanlar BEGINtabloların) yerine girdi dosya adları.

Bu gibi şeylerde faydalı olabilir:

awk '{print $1}' FS=/ RS='\n' file1 FS='\n' RS= file2

Farklı FS/ RSdosya başına belirtebilirsiniz . Aynı zamanda yaygın olarak kullanılır:

awk '!file1_processed{a[$0]; next}; {...}' file1 file1_processed=1 file2

Hangisi daha güvenli bir versiyonudur:

awk 'NR==FNR{a[$0]; next}; {...}' file1 file2

( file1boşsa çalışmaz )

Ancak, adı =karakter içeren dosyalarınız olduğunda bu da olur .

Şimdi, bu yalnızca birinciden geriye kalan =geçerli bir awkdeğişken ismi olduğunda sorun olur .

awkİçinde geçerli bir değişken ismi oluşturan şey, içinde olduğundan daha katıdır sh.

POSIX, bunun gibi bir şey olmasını gerektirir:

[_a-zA-Z][_a-zA-Z0-9]*

Taşınabilir karakter kümesinin sadece karakterleri ile. Bununla birlikte, /usr/xpg4/bin/awkSolaris 11 en azından bu konuda uyumlu değildir ve sadece a-zA-Z yerine değişken isimlerinde yerel ayardaki herhangi bir alfabetik karaktere izin vermez.

Gibi bir argüman Yani x+y=fooya =barya ./foo=barne kaldıysa hala bir giriş dosya adı değil, bir görev olarak kabul edilir ilk =geçerli bir değişken adı değil. Gibi bir argüman Stéphane=Chazelas.txt, awkuygulamaya ve yerel ayara bağlı olarak olabilir veya olmayabilir .

Bu yüzden awk ile kullanılması önerilir:

awk '...' ./*.txt

yerine

awk '...' *.txt

örneğin, problemi önlemek için txtdosyaların isimlerinin =karakter içermeyeceğini garanti edemezseniz.

Ayrıca, -vfoo=bar.txtaşağıdaki gibi bir argümanın bir seçenek olarak değerlendirilebileceğini unutmayın:

awk -f file.awk -vfoo=bar.txt

(ayrıca uygulanır awk '{code}' -vfoo=bar.txtile awkbusybox sürümlerden önce 1.28.0 için, bkz hata raporu tekabül ).

Yine, ./*.txtbunun etrafındaki işleri kullanmak ( ./önek kullanmak, bunun yerine -başka bir yerde standart girdiawk olarak anlayan bir dosyaya da yardımcı olur ).

Bu yüzden de

#! /usr/bin/awk -f

Shebangs gerçekten çalışmıyor. İken var=valueolanları tarafından çalışılan sabitlemeARGV değerleri (a eklemek ./bir de önek) BEGINdeyimi:

#! /usr/bin/awk -f
BEGIN {
  for (i = 1; i < ARGC; i++)
    if (ARGV[i] ~ /^[_[:alpha:]][_[:alnum:]]*=/)
      ARGV[i] = "./" ARGV[i]
}
# rest of awk script

Bu seçeneklerin senaryolarda awkdeğil gördükleri gibi olanlarına yardımcı olmaz awk.

Bu ./öneki kullanmanın olası kozmetik sorunlarından biri de sona ermesidir FILENAME, ancak substr(FILENAME, 3)istemiyorsanız onu soyunmak için her zaman kullanabilirsiniz .

GNU uygulaması awktüm bu sorunları -Eseçeneği ile düzeltir .

Daha sonra -E, gawk yalnızca awkbetiğin yolunu ( -hala stdin anlamına gelir) ve ardından yalnızca giriş dosyası yollarının bir listesini (ve orada -özel olarak bile işlenmez) bekler .

Özellikle şunlar için tasarlandı:

#! /usr/bin/gawk -E

Bağımsız değişkenler listesinin her zaman girdi dosyaları olduğu shebangs (bu ARGVlisteyi bir BEGINifadede düzenlemekte hala özgür olduğunuzu unutmayın ).

Ayrıca olarak kullanabilirsiniz:

gawk -e '...awk code here...' -E /dev/null *.txt

Biz kullanmak -Eboş bir komut ile ( /dev/nullsadece emin olanlar olmak üzere) *.txtiçerdikleri bile, sonradan her zaman girdi dosyaları gibi davranılır =karakterleri.


FILENAME içinde biten açık yolun bir sorun olduğunu anlamıyorum. Ya awk komut o (dahil ancak bunlarla sınırlı olmamak FILENAME biten yolları her türlü işlemesi gerektiğini, bu durumda, geneldir ../foo, /path/to/foodava hangi - Farklı kodlamada ve yollar) substr(FILENAME,3)yeterli olmayacaktır, ya da var kullanıcının dosya adlarının ne olduğunu bildiği tek vuruşlu bir senaryo - bu durumda muhtemelen bunlardan herhangi =birini içeren rahatsız edici olmamalıdır ;-)
mosvy

2
@ mosvy Bunun ./bir sorun olduğunu çok fazla ifade etmediğini düşünüyorum , ancak dosya adının çıktıya dahil edilmesi gereken durumlar gibi belirli koşullar altında istenmeyebilir, bu durumda ./gereksiz ve gereksiz olmalı, bu nedenle Bir şekilde ondan kurtulmak gerekecek. İşte en az bir örnek . Kullanıcının dosya adlarının ne olduğunu bildiği gibi - bu durumda, dosya adının ne olduğunu da biliyoruz, ancak =yine de düzgün bir şekilde işlemeye devam ediyor. Böylece lider -yoluna girebilir .
Sergiy Kolodyazhnyy

@ mosvy, evet fikir şu (yanlış) özelliği ./etrafında çalışmak için önek kullanmak istediğiniz awkancak daha sonra ./çıktısını almak isteyebileceğiniz bir çıkışla bitirdiniz . Bkz dosyanın ilk satırı belirli bir dize içeriyorsa nasıl kontrol edeceğinizi? Örnek olarak.
Stéphane Chazelas

Yalnızca yerel (bu dizine göre) ./değil, aynı zamanda /awk'yi yapan global (mutlak yol) argümanı bir dosya olarak yorumluyor.
Isaac,

21

Awk sürümlerinin çoğunda, programın çalıştırılacağı argümanlarından biri şunlardır:

  1. Bir dosya
  2. Formun bir ödevi x=y

Dosya adınız 2 no'lu vaka olarak yorumlandığından, awk hala stdin'de okunacak bir şeyler bekliyor (çünkü herhangi bir dosya adının geçtiğini algılamıyor).

Taşınabilir olarak, bu davranış POSIX’de belgelenmiştir :

Aşağıdaki iki tür argümandan herhangi biri birbirine karışabilir:

  • file: Programdaki desen setiyle eşleşen okunacak girişi içeren dosyanın bir dosya adı. Dosya işleci belirtilmemişse veya bir dosya işleni '-' ise, standart girdi kullanılır.
  • atama: Taşınabilir karakter kümesinden alt çizgi veya alfabetik bir karakterle başlayan bir işlenen (IEEE Std 1003.1-2001, Bölüm 6.1, Taşınabilir Karakter Kümesinin Temel Tanımlamaları hacmindeki tabloya bakın), ardından bir alt çizgi, rakam dizisi, ve portatif karakter setinden gelen alfabetikler ve ardından '=' karakteri, bir yol adı yerine değişken bir atama belirtmelidir.

Gibi, taşınabilir, birkaç seçeneğiniz var (# 1 muhtemelen en az müdahaleci):

  1. awk ... ./my=fileBu ., çünkü "taşınabilir karakter kümesinden bir alt çizgi ya da alfabetik karakter" olmadığından, bunu yok eden kullanımı kullanın .
  2. Dosyayı kullanarak stdin üzerine yerleştirin awk ... < my=file. Ancak, bu birden fazla dosyayla iyi çalışmaz.
  3. Geçici olarak dosyaya bir bağlantı yapın ve bunu kullanın. Gibi bir şey yapabilir ln my=file my_fileve sonra my_filenormal olarak kullanabilirsiniz . Hiçbir kopyalama yapılmayacak ve her iki dosya da aynı veriler ve inode meta verileri ile desteklenecektir. Kullandıktan sonra, inode'a referans sayısı hala 0'dan büyük olacağından oluşturulan bağlantıyı kaldırmak güvenlidir.

6
Does not ./my=file çalışmak? % awk 'processing_script_here' ./my=file.txt awk: fatal: cannot open file ./my=file.txt' for reading (No such file or directory). Bu taşınabilir olmalıdır ./my, çünkü geçerli bir değişken adı değildir, bu nedenle ayrıştırılmamalıdır.
Stephen Harris,

2
POSIX metninin dediği gibi, sorun yalnızca =birincinin taşınabilir karakter kümesinden alt çizgi veya alfabetik bir karakterden önce gelmesidir (IEEE Std 1003.1-2001, Bölüm 6.1, Taşınabilir Karakter Kümesi Temel Tanımları hacmindeki tabloya bakınız), taşınabilir karakter kümesinden bir dizi alt çizgi, rakam ve alfabetik izler . yani bir dosya yolu ++foo=bar.txtya =fooda benzeri ya da ./foo=barhepsi tamam .ya +da değil [_a-zA-Z].
Stéphane Chazelas,

1
@SergiyKolodyazhnyy awk kabuğun dışındadır, dolayısıyla hangisini kullandığınız önemli değildir. ./my=fileVerbatimden geçilecek.
Chris Down,

1
@SergiyKolodyazhnyy, aynı için awk '{print $1,$2}' /etc/passwd. Mesele şu ki, kabuğun dosyayı awk yerine açması, aranabilir olup olmamasına göre bir fark yaratmaz. Aslında, oradaki pozisyonda awk '{exit}' < /etc/passwdkaldığından emin olmak awkiçin ilk kaydın sonuna kadar geri dönmeyi beklersiniz exit. POSIX bunu gerektirir. /usr/xpg4/bin/awkSolaris üzerinde yapar, ancak ne gawkde mawkGNU / Linux üzerinde bunu yapmak gibi görünüyor.
Stéphane Chazelas

3
@ mosvy, pubs.opengroup.org/onlinepubs/9699919799/utilities/… adresindeki INPUT FILES bölümüne bakın. Sadece bir dosyayı kısaltmak veya içine veri yazmak istediğinizde olduğu gibi normal dosyalar için mantıklı olan birçok kullanım biçiminde kullanışlıdır. awkbu şekilde tanımlanan bir pozisyon .
Stéphane Chazelas

3

Gawk belgelerini alıntılamak için (vurgunun eklendiğine dikkat edin):

Komut satırındaki tüm ek argümanlar normalde belirtilen sırada işlenecek giriş dosyaları olarak kabul edilir. Ancak, var = value şeklinde bir argüman, değer değerini var değişkenine atar - bir dosya belirtmez.

Komut neden durur ve bekler? Formda , yukarıdaki tanımda awk 'processing_script_here' my=file.txt belirtilen hiçbir dosya bulunmadığından - my=file.txtdeğişken atama olarak yorumlanır ve tanımlanmış bir dosya yoksa, awkstdin okuyacak (aynı zamanda stracebu komuttaki read(0,'...)awk'nin sistem çağrısı için beklediğini gösteren açıktır) .

Bu ayrıca POSIX awk teknik özelliklerinde belgelenmiştir , bkz. OPERANDS bölümü ve bunun bir kısmı atama )

Değişken atama, / etc / passwd içindeki her satır için awk '{print foo}' foo=bar /etc/passwdbu değerin foobasılmasında belirgindir . ./foo=barAncak tam yol veya belirtmek işe yarıyor.

Not o çalışan straceüzerinde awk '1' foo=baryanı sıra danışmadan cat foo=barawk'nın özgü bir sorundur ve argüman geçerken kabuklar bu durumda env değişken atamaları ile ilgisi olmayan bu yüzden execve, gösteri dosya adını yaptığı gösteriler.

Ek olarak, awk '...script...' foo=barçevre değişken atamalarının etkili olması için bir komuttan önce gelmesi gerektiğinden, kabuk tarafından ortam değişkeni oluşturmaya neden olmayacağını lütfen unutmayın . Bkz POSIX Kabuk Dilbilgisi Kuralları , nokta sayısı 7. Ayrıca bu aracılığıyla doğrulanabilirawk '{print ENVIRON["foo"]}' foo=bar /etc/passwd

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.