シェルスクリプト間で入力データを交換する

シェルスクリプト間で入力データを交換する

Android adb シェルで実行する簡単なシェル スクリプトがあります。

while true; do
    read var1
    echo $var1 > /data/local/tmp/debug.txt
    am force-stop $var1
done

元のシェル インスタンスのコンソールに値を入力すると正常に動作します。ただし、別の adb シェルを開いて最初のプロセスにデータを渡そうとすると、次のようになります。

echo "com.package.name" > /proc/XXXX/fd/0

ここで、XXXX は最初のシェルの pid です。文字列 "com.package.name" が最初のシェルの に到着することだけがわかりますreadが、デバッグecho行もam行も実行されません。つまり、スクリプトは何か、おそらく改行文字を待っているようですが、 2 番目のシェル入力に 、引数\n-eおよびその他のものを追加しても役に立ちませんでした。

シェル スクリプト間でデータを適切に渡すにはどうすればよいですか?

答え1

あなたは、よくある概念に惑わされています。Linuxシステム内の全てはファイルであるこれを説明するために、私はあなたのコマンドを というファイルに入れてforever、プロセスのPIDを見つけ、

$ file /proc/25546/fd/*
  /proc/25546/fd/0:   symbolic link to `/dev/pts/12' 
  /proc/25546/fd/1:   symbolic link to `/dev/pts/12' 
  /proc/25546/fd/2:   symbolic link to `/dev/pts/12' 
  /proc/25546/fd/255: symbolic link to `/home/me/tmp/forever'
 $ file /dev/pts/12
  /dev/pts/12: character special

これは、ファイル記述子1、2、3が文字ファイルであることを示しています。これはよく知られています(たとえば、UnixとLinuxでのこの回答) それ:

キャラクタデバイス(キャラクタスペシャルファイルとも呼ばれる)は、パイプやシリアルポートなどのように動作します。書き込みや読み取りは即時に行われます。しかし、ドライバがデータに対して行う処理は、独自のビジネスキャラクタ デバイスにバイトを書き込むと、画面に表示されたり、シリアル ポートに出力されたり、サウンドに変換されたりする可能性があります。デバイスからバイトを読み取ると、シリアル ポートが入力を待機したり、ランダム バイト (/dev/urandom) が返されたりする可能性があります。

したがって、IPC (プロセス間通信) を実行するには別の方法が必要です。UnixとLinuxの場合、 がある 名前付きパイプこのため、スクリプトを次のように変更します。

#!/bin/bash

MYPIPE=/tmp/my_pipe
if [[ ! -p $MYPIPE ]]; then
     mkfifo $MYPIPE
fi

while true
do
     if read line <$pipe; then
         if [[ "$line" == 'quit' ]]; then
            break
         fi
         echo $line >> /tmp/debug.txt
     fi
done

echo "I quit"

スクリプトを開始します。別のターミナルから入力してください。

 $ cat > /tmp/my_pipe
   My name is 
   George Washington 
    ....

3 番目のターミナルから を使用するとtail -f /tmp/debug.txt、2 番目のターミナルに入力した内容が から再表示されます/tmp/debug.txt

Androidの場合状況はもう少し複雑ですが、ここそしてここルート化されていない Android デバイスで名前付きパイプを作成する問題を回避する 2 つの異なる方法 (最初の方法は 2 番目の方法よりも簡単です)。

関連情報