ホームページ  >  記事  >  システムチュートリアル  >  初心者から熟練者まで、ワークフローをスピードアップするための Linux リダイレクトとパイプライン ツールを学びましょう。

初心者から熟練者まで、ワークフローをスピードアップするための Linux リダイレクトとパイプライン ツールを学びましょう。

PHPz
PHPz転載
2024-02-09 23:36:381200ブラウズ

作業効率の向上、オペレーティング システムの最適化、自動化などは、すべての IT 担当者が追求する目標です。 Linux オペレーティング システムでは、リダイレクトおよびパイプライン コマンド ライン ツールを巧みに使用できることは、習得しなければならないスキルの 1 つです。この記事では、リダイレクト ツールとパイプライン ツールの使用法と原理を例を用いて詳しく説明します。

私は Linux システムがとても好きです。特に Linux のデザインの一部はとても美しいです。たとえば、いくつかの複雑な問題はいくつかの小さな問題に分解でき、パイプ文字を通じて既製のツールを使用して柔軟に解決できます。リダイレクトメカニズムはシェルスクリプトとして記述でき、非常に効率的です。

初心者から熟練者まで、ワークフローをスピードアップするための Linux リダイレクトとパイプライン ツールを学びましょう。

この記事では、実際にリダイレクトとパイプ文字を使用するときに遭遇した落とし穴のいくつかを紹介します。基礎となる原則を理解すると、スクリプト作成の効率が大幅に向上します。

#>> および >> リダイレクト文字の落とし穴

まず最初の質問について話しましょう。次のコマンドを実行するとどうなりますか?

リーリー

同じファイルの読み取りと書き込みは、何も起こらないように感じますよね?

実際には、上記のコマンドを実行すると、file.txt ファイルの内容が消去されます。

PS: 一部の Linux ディストリビューションではエラーが直接報告される場合があります。catfile.txt を実行すると、この検出を回避できます。

Linux プロセスとファイル記述子について上で述べたように、プログラム自体は標準入出力のポイントを気にする必要はなく、パイプ文字とリダイレクトを通じてプログラムの標準入出力の場所を変更するのはシェルです。シンボル。

したがって、cat file.txt > file.txt コマンドを実行すると、シェルは最初に file.txt を開きます。リダイレクト記号は > であるため、ファイル内の内容はクリアされ、その後、シェルは標準を設定します。 cat コマンドの出力は file.txt であり、cat コマンドの実行が開始されます。

それは次のプロセスです:

1. シェルは file.txt を開き、その内容をクリアします。

2. シェルは、cat コマンドの標準出力を file.txt ファイルにポイントします。
3. シェルは cat コマンドを実行し、空のファイルを読み取ります。
4. cat コマンドは、空の文字列を標準出力 (file.txt ファイル) に書き込みます。

つまり、最終的な結果は、file.txt が空のファイルになります。

> はターゲット ファイルをクリアし、>> はターゲット ファイルの末尾にコンテンツを追加することがわかっています。では、リダイレクト記号 > が >> に変更されるとどうなりますか?

リーリー

最初に 1 行のコンテンツが file.txt に書き込まれます。cat file.txt >> file.txt を実行すると、期待される結果は 2 行のコンテンツになるはずです。

残念ながら、実行結果は期待どおりではありません。代わりに、無限ループで file.txt に hello world を書き込み続けます。ファイルはすぐに非常に大きくなり、コマンドは Control C でのみ停止できます。

これは興味深いですね。なぜ無限ループが発生するのでしょうか?実際、少し分析すると、その理由を考えることができます:

まず、cat コマンドの動作を思い出してください。cat コマンドのみを実行すると、キーボード入力がコマンド ラインから読み取られます。Enter キーを押すたびに、cat コマンドは入力をエコーし​​ます。つまり、 cat コマンド データを一行ずつ読み込んで出力します。

次に、cat file.txt >> file.txt コマンドの実行プロセスは次のとおりです。

1. file.txt を開いて、ファイルの末尾にコンテンツを追加する準備をします。

2. cat コマンドの標準出力が file.txt ファイルを指すようにします。
3. cat コマンドは、file.txt 内の内容の 1 行を読み取り、それを標準出力 (file.txt ファイルに追加) に書き込みます。
4. データ行が書き込まれたばかりなので、cat コマンドは file.txt に読み取ることができるコンテンツがまだあることを検出し、ステップ 3 を繰り返します。

上記のプロセスは、リストを走査し、同時にリストに要素を追加するようなものです。完全に走査されることはないため、コマンドは無限ループになります。

#>> リダイレクト文字と | パイプ文字は連携して機能します

ファイルの最初の XX 行をインターセプトし、残りを削除するというような要件に遭遇することがよくあります。

Linux では、head コマンドはファイルの最初の数行をインターセプトする機能を完了できます。

リーリー

ファイルの最初の 2 行を保持し、他の行を削​​除したい場合は、次のコマンドを使用します。

リーリー

しかし、これは上で述べた間違いを引き起こし、最終的には file.txt が消去されるため、私たちのニーズを満たすことができません。

次のようなコマンドを記述することで落とし穴を回避できますか:

リーリー

結論としては、これは機能せず、ファイルの内容は依然として消去されます。

何?パイプラインにリークがあり、すべてのデータが欠落しているのでしょうか?

前回の記事「Linux プロセスとファイル記述子」では、パイプ文字の実装原理は基本的に 2 つのコマンドの標準入力と標準出力を接続し、前のコマンドの標準出力を使用できるようにすることであるとも述べました。次のコマンドの標準入力として使用します。

ただし、このようにコマンドを書けば期待通りの結果が得られると思っている場合は、パイプ文字で結ばれたコマンドが連続して実行されると考えているためかもしれません。これはよくある間違いです。実際には、複数のコマンドがパイプ文字で結ばれています。パイプ文字はシリアルに実行され、パラレルに実行されます。

シェルは最初に cat file.txt コマンドを実行し、file.txt 内のすべての内容を通常どおり読み取り、次にこれらの内容をパイプ経由で head -n 2 > file.txt コマンドに渡すと考えるかもしれません。

このとき file.txt の内容はクリアされますが、head はファイルからデータを読み取るのではなく、パイプからデータを読み取るので、正しく file.txt に 2 行のデータを書き込むことができるはずです。

但实际上,上述理解是错误的,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操作系统中,重定向和管道是非常有用的命令行工具,可以让我们更好地掌握系统的运行状态和信息。掌握相关技能能够帮助我们更好地进行系统优化和自动化工作,从而更好地提高工作效率。相信通过本文的介绍,读者对重定向和管道的原理和使用方法都有了更为深入的了解。

以上が初心者から熟練者まで、ワークフローをスピードアップするための Linux リダイレクトとパイプライン ツールを学びましょう。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlxlinux.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。