awk 'processing_script_here' my=file.txt
belirsiz bir süre durup beklemeye benziyor ...
Burada neler oluyor ve nasıl çalıştırabilirim?
awk 'processing_script_here' my=file.txt
belirsiz bir süre durup beklemeye benziyor ...
Burada neler oluyor ve nasıl çalıştırabilirim?
Yanıtlar:
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 BEGIN
tabloların) yerine girdi dosya adları.
Bu gibi şeylerde faydalı olabilir:
awk '{print $1}' FS=/ RS='\n' file1 FS='\n' RS= file2
Farklı FS
/ RS
dosya 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
( file1
boş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 awk
değ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/awk
Solaris 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=foo
ya =bar
ya ./foo=bar
ne 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
, awk
uygulamaya 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 txt
dosyaların isimlerinin =
karakter içermeyeceğini garanti edemezseniz.
Ayrıca, -vfoo=bar.txt
aş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.txt
ile awk
busybox sürümlerden önce 1.28.0 için, bkz hata raporu tekabül ).
Yine, ./*.txt
bunun 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=value
olanları tarafından çalışılan sabitlemeARGV
değerleri (a eklemek ./
bir de önek) BEGIN
deyimi:
#! /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 awk
değ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ı awk
tüm bu sorunları -E
seçeneği ile düzeltir .
Daha sonra -E
, gawk yalnızca awk
betiğ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 ARGV
listeyi bir BEGIN
ifadede düzenlemekte hala özgür olduğunuzu unutmayın ).
Ayrıca olarak kullanabilirsiniz:
gawk -e '...awk code here...' -E /dev/null *.txt
Biz kullanmak -E
boş bir komut ile ( /dev/null
sadece emin olanlar olmak üzere) *.txt
içerdikleri bile, sonradan her zaman girdi dosyaları gibi davranılır =
karakterleri.
../foo
, /path/to/foo
dava 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 ;-)
./
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 .
./
etrafında çalışmak için önek kullanmak istediğiniz awk
ancak 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.
./
değil, aynı zamanda /
awk'yi yapan global (mutlak yol) argümanı bir dosya olarak yorumluyor.
Awk sürümlerinin çoğunda, programın çalıştırılacağı argümanlarından biri şunlardır:
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):
awk ... ./my=file
Bu .
, çünkü "taşınabilir karakter kümesinden bir alt çizgi ya da alfabetik karakter" olmadığından, bunu yok eden kullanımı kullanın .awk ... < my=file
. Ancak, bu birden fazla dosyayla iyi çalışmaz.ln my=file my_file
ve sonra my_file
normal 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../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.
=
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.txt
ya =foo
da benzeri ya da ./foo=bar
hepsi tamam .
ya +
da değil [_a-zA-Z]
.
./my=file
Verbatimden geçilecek.
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/passwd
kaldığından emin olmak awk
için ilk kaydın sonuna kadar geri dönmeyi beklersiniz exit
. POSIX bunu gerektirir. /usr/xpg4/bin/awk
Solaris üzerinde yapar, ancak ne gawk
de mawk
GNU / Linux üzerinde bunu yapmak gibi görünüyor.
awk
bu şekilde tanımlanan bir pozisyon .
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.txt
değişken atama olarak yorumlanır ve tanımlanmış bir dosya yoksa, awk
stdin okuyacak (aynı zamanda strace
bu 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/passwd
bu değerin foo
basılmasında belirgindir . ./foo=bar
Ancak tam yol veya belirtmek işe yarıyor.
Not o çalışan strace
üzerinde awk '1' foo=bar
yanı sıra danışmadan cat foo=bar
awk'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