Meningkatkan kecekapan kerja, pengoptimuman sistem pengendalian, automasi, dsb. adalah matlamat yang diusahakan oleh setiap pengamal IT. Dalam sistem pengendalian Linux, berkebolehan menggunakan alat arahan ubah hala dan saluran paip adalah salah satu kemahiran yang mesti dikuasai. Artikel ini akan menerangkan secara terperinci penggunaan dan prinsip alat pengalihan dan saluran paip melalui contoh.
Saya sangat menyukai sistem Linux, terutamanya beberapa reka bentuk Linux yang sangat cantik Sebagai contoh, beberapa masalah yang kompleks boleh diuraikan kepada beberapa masalah kecil, dan boleh diselesaikan secara fleksibel dengan alat siap pakai melalui watak paip dan pengalihan. Mekanisme ini sangat cekap untuk menulis skrip shell.
Artikel ini akan berkongsi beberapa masalah yang saya temui dalam menggunakan pengalihan dan aksara paip dalam amalan Memahami beberapa prinsip asas boleh meningkatkan kecekapan penulisan skrip.
Perangkap> dan >> Ubah Hala Watak
Mari kita bincangkan tentang soalan pertama dahulu, apakah yang akan berlaku jika anda melaksanakan arahan berikut?
$ cat file.txt > file.txt
Membaca dan menulis pada fail yang sama rasanya seperti tiada apa yang akan berlaku, bukan?
Malah, hasil menjalankan arahan di atas adalah untuk mengosongkan kandungan fail file.txt.
PS: Sesetengah pengedaran Linux mungkin melaporkan ralat secara langsung Anda boleh melaksanakan catfile.txt untuk memintas pengesanan ini.
Seperti yang dinyatakan dalam artikel sebelum ini tentang proses Linux dan deskriptor fail, program itu sendiri tidak perlu mengambil berat tentang di mana titik input/output standardnya Ia adalah shell yang mengubah lokasi input/output standard program melalui aksara paip dan simbol ubah hala.
Jadi apabila melaksanakan perintah cat file.txt > file.txt, shell akan mula-mula membuka file.txt Memandangkan simbol ubah hala ialah >, kandungan fail akan dikosongkan, dan kemudian shell akan menetapkan output standard. perintah kucing untuk memfailkan .txt, kemudian perintah kucing mula dilaksanakan.
Iaitu, proses berikut:
1 Shell membuka file.txt dan mengosongkan kandungannya.
2. Shell menghalakan output standard arahan kucing ke fail file.txt.
3. Cangkang melaksanakan perintah kucing dan membaca fail kosong.
4. Perintah kucing menulis rentetan kosong ke output standard (fail.txt fail).
Jadi, keputusan akhir ialah file.txt menjadi fail kosong.
Kami tahu bahawa > akan mengosongkan fail sasaran dan >> akan menambahkan kandungan pada penghujung fail sasaran, jadi apakah yang akan berlaku jika simbol ubah hala > ditukar kepada >>?
$ echo hello world > file.txt # 文件中只有一行内容 $ cat file.txt >> file.txt # 这个命令会死循环
Satu baris kandungan mula-mula ditulis ke dalam file.txt Selepas melaksanakan cat file.txt >> file.txt, hasil yang dijangkakan hendaklah dua baris kandungan.
Tetapi malangnya, hasil larian tidak seperti yang dijangkakan, sebaliknya, ia akan terus menulis hello world ke file.txt dalam gelung tak terhingga Fail akan menjadi sangat besar tidak lama lagi dan arahan hanya boleh dihentikan dengan Control+C.
Menariknya, kenapa ada infinite loop sebenarnya, lepas analisis sikit boleh fikir sebabnya:
Pertama, ingat semula tingkah laku arahan kucing Jika anda hanya melaksanakan perintah kucing, input papan kekunci akan dibaca dari baris arahan Setiap kali anda menekan Enter, arahan kucing akan menggemakan input arahan cat adalah satu demi satu baris membaca data dan kemudian mengeluarkan data.
Kemudian, proses pelaksanaan cat file.txt >> file.txt arahan adalah seperti berikut:
1. Buka file.txt dan sediakan untuk menambahkan kandungan pada penghujung fail.
2. Halakan output standard arahan kucing ke fail file.txt.
3. Perintah kucing membaca baris kandungan dalam file.txt dan menulisnya pada output standard (tambah pada fail file.txt).
4. Memandangkan baris data baru sahaja ditulis, arahan cat mendapati bahawa masih terdapat kandungan yang boleh dibaca dalam file.txt, dan akan mengulangi langkah 3.
Proses di atas adalah seperti melintasi senarai dan menambahkan elemen pada senarai pada masa yang sama Ia tidak akan dilalui sepenuhnya, yang membawa kepada gelung tak terhingga perintah kami.
> Watak ubah hala dan watak paip | Kami sering menghadapi keperluan untuk memintas XX baris pertama fail dan memadamkan selebihnya.
Di Linux, arahan kepala boleh melengkapkan fungsi memintas beberapa baris pertama fail:
$ cat file.txt # file.txt 中有五行内容 1 2 3 4 5 $ head -n 2 file.txt # head 命令读取前两行 1 2 $ cat file.txt | head -n 2 # head 也可以读取标准输入 1 2
Jika kami ingin menyimpan 2 baris pertama fail dan memadamkan selebihnya, kami boleh menggunakan arahan berikut:
$ head -n 2 file.txt > file.txt
Tetapi ini akan membuat kesilapan yang dinyatakan di atas Pada akhirnya, file.txt akan dikosongkan, yang tidak dapat mencapai keperluan kita.
Kemudian jika kita menulis arahan seperti ini, bolehkah kita mengelakkan perangkap:
$ cat file.txt | head -n 2 > file.txt
Kesimpulannya ialah ia tidak berfungsi, kandungan fail masih akan dikosongkan.
Apakah ada kebocoran dalam saluran paip dan semua data hilang?
Dalam artikel sebelumnya tentang proses Linux dan deskriptor fail, saya juga menyebut prinsip pelaksanaan watak paip Pada asasnya, ia menghubungkan input dan output standard dua arahan, supaya output standard arahan sebelumnya berfungsi sebagai input standard. daripada arahan seterusnya.
Namun, jika anda berpendapat bahawa menulis arahan seperti ini boleh mendapatkan hasil yang diharapkan, ini mungkin kerana anda berpendapat bahawa arahan yang disambungkan oleh watak paip dilaksanakan secara bersiri Ini adalah kesilapan biasa watak dilaksanakan secara selari.
Anda mungkin berfikir bahawa shell akan mula-mula melaksanakan perintah cat file.txt, baca semua kandungan dalam file.txt seperti biasa, dan kemudian hantar kandungan ini ke kepala -n 2 > perintah file.txt melalui paip.
Walaupun kandungan dalam file.txt akan dikosongkan pada masa ini, head tidak membaca data daripada fail, tetapi membaca data daripada paip, jadi anda boleh menulis dua baris data ke file.txt dengan betul.
但实际上,上述理解是错误的,shell 会并行执行管道符连接的命令,比如说执行如下命令:
$ sleep 5 | sleep 5
shell 会同时启动两个sleep进程,所以执行结果是睡眠 5 秒,而不是 10 秒。
这是有点违背直觉的,比如这种常见的命令:
$ cat filename | grep 'pattern'
直觉好像是先执行cat命令一次性读取了filename中所有的内容,然后传递给grep命令进行搜索。
但实际上是cat和grep命令是同时执行的,之所以能得到预期的结果,是因为grep ‘pattern’会阻塞等待标准输入,而cat通过 Linux 管道向grep的标准输入写入数据。
执行下面这个命令能直观感受到cat和grep是在同时执行的,grep在实时处理我们用键盘输入的数据:
$ cat | grep 'pattern'
说了这么多,再回顾一开始的问题:
$ cat file.txt | head -n 2 > file.txt
cat命令和head会并行执行,谁先谁后不确定,执行结果也就不确定。
如果head命令先于cat执行,那么file.txt就会被先清空,cat也就读取不到任何内容;反之,如果cat先把文件的内容读取出来,那么可以得到预期的结果。
不过,通过我的实验(将这种并发情况重复 1w 次)发现,file.txt被清空这种错误情况出现的概率远大于预期结果出现的概率,这个暂时还不清楚是为什么,应该和 Linux 内核实现进程和管道的逻辑有关。
解决方案
说了这么多管道符和重定向符的特点,如何才能避免这个文件被清空的坑呢?
最靠谱的办法就是不要同时对同一个文件进行读写,而是通过临时文件的方式做一个中转。
比如说只保留file.txt文件中的头两行,可以这样写代码:
# 先把数据写入临时文件,然后覆盖原始文件
$ cat file.txt | head -n 2 > temp.txt && mv temp.txt file.txt
这是最简单,最可靠,万无一失的方法。
你如果嫌这段命令太长,也可以通过apt/brew/yum等包管理工具安装moreutils包,就会多出一个sponge命令,像这样使用:
# 先把数据传给 sponge,然后由 sponge 写入原始文件 $ cat file.txt | head -n 2 | sponge file.txt
sponge这个单词的意思是海绵,挺形象的,它会先把输入的数据「吸收」起来,最后再写入file.txt,核心思路和我们使用临时文件时类似的,这个「海绵」就好比一个临时文件,就可以避免同时打开同一个文件进行读写的问题。
在Linux操作系统中,重定向和管道是非常有用的命令行工具,可以让我们更好地掌握系统的运行状态和信息。掌握相关技能能够帮助我们更好地进行系统优化和自动化工作,从而更好地提高工作效率。相信通过本文的介绍,读者对重定向和管道的原理和使用方法都有了更为深入的了解。
Atas ialah kandungan terperinci Daripada pemula hingga mahir, pelajari alat pengalihan dan saluran paip Linux untuk mempercepatkan aliran kerja anda!. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!