Ne arasındaki fark var <<
, <<<
ve < <
bash?
Ne arasındaki fark var <<
, <<<
ve < <
bash?
Yanıtlar:
İşte belge
<<
here-document
yapı olarak bilinir . Programa bitiş metninin ne olacağını bildirirsiniz ve bu sınırlayıcı göründüğünde, programa verdiğiniz tüm bilgileri giriş olarak okur ve üzerinde bir görev gerçekleştirir.
İşte demek istediğim:
$ wc << EOF
> one two three
> four five
> EOF
2 5 24
Bu örnekte, wc
programın EOF
string'i beklemesini , ardından beş kelimeyi EOF
yazıp girdi verdiğimizi işaret etmek için yazın . Aslında, wc
tek başına koşmaya , sözcükleri yazmaya ve ardından tuşuna basmaya benzer.CtrlD
Bash'te bunlar geçici dosyalar aracılığıyla, genellikle formda /tmp/sh-thd.<random string>
, tire ise adsız borular olarak uygulanırlar. Bu, sistem çağrıları strace
komut ile izleme yoluyla görülebilir . Bu yönlendirmeyi nasıl gerçekleştirdiğini görmek için bash
ile değiştirin .sh
/bin/sh
$ strace -e open,dup2,pipe,write -f bash -c 'cat <<EOF
> test
> EOF'
İşte dize
<<<
olarak bilinir here-string
. Metin yazmak yerine, bir programa önceden hazırlanmış bir metin dizesi verirsiniz. Örneğin, sadece bu özel durum için çıktı almak için bc
yapabileceğimiz bir programla, bc <<< 5*4
etkileşimli olarak bc çalıştırmaya gerek yoktur.
Burada bash dizeleri, genellikle /tmp/sh-thd.<random string>
daha sonra bağlantısız olan biçimindeki geçici dosyalar aracılığıyla uygulanır , bu nedenle geçici olarak bir miktar bellek alanı kaplarlar, ancak /tmp
dizin girişleri listesinde görünmezler ve yine de isimsiz dosyalar olarak etkin bir şekilde bulunurlar. dosya tanıtıcısı aracılığıyla kabuğun kendisi tarafından referans alınabilir ve bu dosya tanıtıcısı komut tarafından miras alınır ve daha sonra dup2()
işlev aracılığıyla dosya tanıtıcısı 0 (stdin) üzerine çoğaltılır . Bu üzerinden gözlemlenebilir
$ ls -l /proc/self/fd/ <<< "TEST"
total 0
lr-x------ 1 user1 user1 64 Aug 20 13:43 0 -> /tmp/sh-thd.761Lj9 (deleted)
lrwx------ 1 user1 user1 64 Aug 20 13:43 1 -> /dev/pts/4
lrwx------ 1 user1 user1 64 Aug 20 13:43 2 -> /dev/pts/4
lr-x------ 1 user1 user1 64 Aug 20 13:43 3 -> /proc/10068/fd
Ve izleme sistemleri aracılığıyla (okunabilirlik için çıktı kısaltıldı; geçici dosyanın fd 3 olarak nasıl açıldığına, bunun üzerine yazılan verinin nasıl açıldığına dikkat edin, daha sonra O_RDONLY
fd 4 olarak bayrakla yeniden açıldı , daha sonra bağlantısı kaldırıldı, sonra dup2()
fd 0 üzerine, cat
sonradan devralındı. ):
$ strace -f -e open,read,write,dup2,unlink,execve bash -c 'cat <<< "TEST"'
execve("/bin/bash", ["bash", "-c", "cat <<< \"TEST\""], [/* 47 vars */]) = 0
...
strace: Process 10229 attached
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
[pid 10229] write(3, "TEST", 4) = 4
[pid 10229] write(3, "\n", 1) = 1
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDONLY) = 4
[pid 10229] unlink("/tmp/sh-thd.uhpSrD") = 0
[pid 10229] dup2(4, 0) = 0
[pid 10229] execve("/bin/cat", ["cat"], [/* 47 vars */]) = 0
...
[pid 10229] read(0, "TEST\n", 131072) = 5
[pid 10229] write(1, "TEST\n", 5TEST
) = 5
[pid 10229] read(0, "", 131072) = 0
[pid 10229] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=10229, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
Görüş: potansiyel olarak burada dizgiler geçici metin dosyalarını kullandığı için, burada-dizgilerin her zaman sonunda yeni bir satır eklemesi olası bir nedenidir, çünkü POSIX tanımına göre metin dosyasının satırsonu karakterinde biten satırlara sahip olması gerekir.
İşlem Değiştirme
Gibi tldp.org açıklıyor
Süreç ikame işlemi, bir işlemin (ya da işlemlerin) çıktısını başka bir işlemin başlığına besler.
Yani aslında bu boru benzer stdout'u örneğin diğer bir komuta echo foobar barfoo | wc
. Ancak dikkat: bash manpage’de bunun olarak belirtildiğini göreceksiniz <(list)
. Yani temelde çoklu (!) Komutların çıktısını yönlendirebilirsiniz.
Not: teknik < <
olarak tek bir şeye atıfta bulunmadığınızı söylediğinizde , tek <
çıkışlı iki yönlendirme ve çıktının işlem yeniden yönlendirmesidir <( . . .)
.
Şimdi sadece ikame işlemini yaparsak ne olur?
$ echo <(echo bar)
/dev/fd/63
Gördüğünüz gibi, kabuk /dev/fd/63
çıktının gittiği geçici bir dosya tanımlayıcı oluşturur ( Gilles'in cevabına göre isimsiz bir boru). Bu, <
o dosya tanımlayıcısını bir komuta girdi olarak yönlendirir.
Bu yüzden çok basit bir örnek, iki yankı komutundan çıktının işlem yerine wc'ye işlem yapmasıdır:
$ wc < <(echo bar;echo foo)
2 2 8
Bu yüzden burada kabuk parantezde gerçekleşen tüm çıktılar için bir dosya tanıtıcısı yaratır ve bunu, wc
beklendiği gibi, wc'nin her biri kelimesi olan iki satır çıktısı alabilen iki eko komutundan bu akımı aldığı için yönlendiririz . ve uygun bir şekilde 2 kelimemiz, 2 satırımız ve 6 karakterimiz var.
Yan Not: Proses ikamesi bir faşizm ( bash
POSIX tarafından belirtilen ancak POSIX gibi gelişmiş kabuklarda kullanılabilecek bir komut veya yapı ) olarak adlandırılabilir, ancak bu, ksh man sayfasıksh
olarak bash'ın varlığından önce uygulanmıştır ve bu cevabı göstermektedir. Gibi tcsh
ve mksh
ancak kabukları işlem ikamesine sahip değildir. Öyleyse, çoklu komutların çıktısını proses ikame edilmeden başka bir komuta yönlendirmeyi nasıl başarabiliriz? Gruplama artı borular!
$ (echo foo;echo bar) | wc
2 2 8
Etkili olarak bu yukarıdaki örnekte olduğu gibidir, Ancak bu, işlemin yerine kullanılmasından dolayı başlık altında farklıdır, çünkü tüm alt kabuktan stdout wc
ve boruya bağlı stdin yaparız . Öte yandan, işlem değiştirme işlemi, komutun geçici bir dosya tanıtıcısını okumasını sağlar.
Peki, borularla gruplama yapabilirsek, neden işlem ikamesine ihtiyacımız var? Çünkü bazen boru kullanamayız. Aşağıdaki örneği ele alalım - iki komutun çıktılarını diff
(iki dosyaya ihtiyaç duyar ve bu durumda iki dosya tanımlayıcı veriyoruz) karşılaştırabiliriz.
diff <(ls /bin) <(ls /usr/bin)
< <
kişi bir süreç ikamesinden stdin yaparken kullanılır . Böyle bir komut gibi görünebilir: cmd1 < <(cmd2)
. Örneğin,wc < <(date)
< <
tek başına bir şey değildir , işlem değiştirme durumunda, bunun <
başlaması gereken bir şey daha olur<
<<<
, önce Plan 9 rc kabuğunun Unix limanı tarafından, daha sonra zsh, bash ve ksh93 tarafından kabul edildi. O zaman ben buna faşizm demezdim.
echo 'foo' | read; echo ${REPLY}
edecek değil dönmek foo
, çünkü read
- boru bir alt kabuk başlayan bir alt kabukta başlatılır. Ancak, alt-kabuk olmadığından read < <(echo 'foo'); echo ${REPLY}
doğru döner foo
.
< <
bir sözdizimi hatası:
$ cat < <
bash: syntax error near unexpected token `<'
< <()
bir işlem ikame ( <()
(yönlendirme ile bir arada) <
):
Kararlı bir örnek:
$ wc -l < <(grep ntfs /etc/fstab)
4
$ wc -l <(grep ntfs /etc/fstab)
4 /dev/fd/63
İşlem değişikliği ile, dosya tanımlayıcısının yolu dosya adı gibi kullanılır. Bir dosya adını doğrudan kullanmak istemiyorsanız (veya kullanamıyorsanız), işlem değiştirmeyi yeniden yönlendirme ile birleştirirsiniz.
Açık olmak gerekirse, < <
operatör yok .
<()
, dosya adı benzeri bir şey verir, bu yüzden daha genel olarak kullanışlıdır - stdin'in gerekmeyeceği < <()
yeri değiştiriyor. İçinde wc
, ikincisi daha faydalı olur. Başka yerde daha az faydalı olabilir
< <
bir sözdizimi hatasıdır, muhtemelen command1 < <( command2 )
bir işlem değiştirme işleminin ardından basit bir giriş yeniden yönlendirmesi olan ve çok benzer, ancak buna eşdeğer olmayan demek
command2 | command1
Çalıştırdığınız varsayarak fark bash
edilir command1
ilki mevcut kabukta çalıştırılır iken, ikinci durumda bir alt kabukta çalıştırılır. Bu, ayarlanan değişkenlerin command1
proses ikame varyantı ile kaybolmayacağı anlamına gelir .
< <
bir sözdizimi hatası verir. Doğru kullanım aşağıdaki gibidir:
Örneklerin yardımıyla açıklama:
Örnek < <()
:
while read line;do
echo $line
done< <(ls)
Yukarıdaki örnekte, while döngüsüne giriş ls
satır satır okunabilecek echo
ve döngüde ed komutundan gelecektir .
<()
işlem ikamesi için kullanılır. Daha fazla bilgi ve örnek <()
bu linkte bulunabilir: