最後に実行したコマンドの結果を後続のコマンドで使用できるようにしたいと思います。例えば、
$ find . -name foo.txt
./home/user/some/directory/foo.txt
ここで、エディターでファイルを開く、削除する、または何か他のことを実行できるようにしたいとします。
mv <some-variable-that-contains-the-result> /some/new/location
どうすればいいですか?多分bash変数を使用していますか?
更新:
明確にするために、物事を手動で割り当てたくありません。私が望んでいるのは、組み込みのbash変数のようなものです.
ls /tmp
cd $_
$_
は、前のコマンドの最後の引数を保持します。似たようなものが欲しいのですが、最後のコマンドの出力が必要です。
最終更新:
セスの答えは非常にうまくいきました。心に留めておくべきいくつかのこと:
touch /tmp/x
を忘れないでくださいこれは本当にハッキーな解決策ですが、ほとんどの場合はうまくいくようです。テスト中、私は時々、 ^C コマンドラインで、動作を少し改善するために少し調整しましたが。
このハックはインタラクティブモードハックのみであり、誰にもお勧めできないと確信しています。バックグラウンドコマンドは、通常よりも定義されていない動作を引き起こす可能性があります。他の答えは、プログラムで結果を取得するより良い方法です。
そうは言っても、ここに「解決策」があります。
Prompt_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)'
このbash環境変数を設定し、必要に応じてコマンドを発行します。 $LAST
は通常、探している出力を持ちます。
startide seth> fortune
Courtship to marriage, as a very witty prologue to a very dull play.
-- William Congreve
startide seth> echo "$LAST"
Courtship to marriage, as a very witty prologue to a very dull play.
-- William Congreve
私はこれを行う変数を知りません自動的に。結果をコピー&ペーストするだけでなく、何かを行うために、今やったことを何でもやり直すことができます。例えば
vim $(!!)
!!
は、「前のコマンド」を意味する履歴展開です。
適切な引数の解析を妨げる可能性のあるスペースまたは他の文字を含む単一のファイル名があると予想される場合は、結果を引用符で囲みます(vim "$(!!)"
)。スペースやその他のシェル解析トークンが含まれていない限り、引用符を付けずに複数のファイルを一度に開くことができます。
Bashは一種のい言語です。はい、出力を変数に割り当てることができます
MY_VAR="$(find -name foo.txt)"
echo "$MY_VAR"
ただし、find
が1つの結果のみを返し、キャリッジリターンやラインフィードなどの「奇妙な」文字が含まれていないことを強く願ってください。 。
ただし、変数を使用するときは、変数を正しく引用するよう注意してください。
ファイルを直接操作することをお勧めします。 find
の-execdir
で(マニュアルを参照してください)。
find -name foo.txt -execdir vim '{}' ';'
または
find -name foo.txt -execdir rename 's/\.txt$/.xml/' '{}' ';'
これを行う方法は複数あります。 1つの方法は、v=$(command)
を使用して、コマンドの出力をv
に割り当てることです。例えば:
v=$(date)
echo $v
また、逆引用符も使用できます。
v=`date`
echo $v
Bash初心者ガイド から
旧形式のバッククォート形式の置換が使用される場合、バックスラッシュは、「$」、「 `」、または「\」が続く場合を除き、リテラルの意味を保持します。バックスラッシュが前に付いていない最初のバックティックは、コマンド置換を終了します。 「$(COMMAND)」形式を使用する場合、括弧で囲まれたすべての文字がコマンドを構成します。特別に扱われるものはありません。
編集:質問の編集後、これはOPが探しているものではないようです。私の知る限り、最後のコマンドの出力には$_
のような特別な変数はありません。
とても簡単です。逆引用符を使用します。
var=`find . -name foo.txt`
そして、あなたは将来いつでもそれを使用することができます
echo $var
mv $var /somewhere
シェルを含むスクリプトにシェルを設定することを含むソリューションをハッキングできる可能性があると思います:
#!/bin/sh
bash | tee /var/log/bash.out.log
$Prompt_COMMAND
を設定して区切り文字を出力する場合、そのログの最後のチャンクを取得するヘルパー関数(_
と呼ばれることもあります)を記述することができるため、次のように使用できます。
% find lots*of*files
...
% echo "$(_)"
... # same output, but doesn't run the command again
免責事項:
Tmuxでインタラクティブシェルを実行すると、ターミナルに現在表示されているデータに簡単にアクセスできます。いくつかの興味深いコマンドを見てみましょう。
ええ、これは今、多くの可能性を与えてくれます:)私に関しては、alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1"
という簡単なエイリアスを設定し、最後の行にアクセスする必要があるたびに$(L)
を使用して取得します。
これは、プログラムが使用する出力ストリーム(stdinまたはstderr)、印刷方法(ncursesなど)、およびプログラムの終了コードとは無関係です。データを表示するだけです。
Bashプロファイルで次のエイリアスを設定できます。
alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))'
次に、任意のコマンドの後に「s」と入力すると、結果をシェル変数「it」に保存できます。
したがって、使用例は次のようになります。
$ which python
/usr/bin/python
$ s
$ file $it
/usr/bin/python: symbolic link to `python2.6'
ここでの提案からこのbash
関数を抽出しました。
grab() {
grab=$("$@")
echo $grab
}
次に、あなたはただ:
> grab date
Do 16. Feb 13:05:04 CET 2012
> echo $grab
Do 16. Feb 13:05:04 CET 2012
更新:匿名ユーザーは、echo
をprintf '%s\n'
に置き換えることを提案しました。これは、取得したテキストの-e
などのオプションを処理しないという利点があります。したがって、このような特性を期待または経験している場合は、この提案を検討してください。別のオプションは、代わりにcat <<<$grab
を使用することです。
バックティックを使用して出力をキャプチャします。
output=`program arguments`
echo $output
emacs $output
「最後に実行したコマンドの結果を後続のコマンドで使用できるようにしたい」と言うことで、私は-単に検索ではなく、任意のコマンドの結果を意味します。
もしそうなら-xargsはあなたが探しているものです。
find . -name foo.txt -print0 | xargs -0 -I{} mv {} /some/new/location/{}
または、最初に出力を確認したい場合:
find . -name foo.txt -print0
!! | xargs -0 -I{} mv {} /some/new/location/{}
このコマンドは複数のファイルを処理し、パスやファイル名にスペースが含まれている場合でもチャームのように機能します。
mv {}/some/new/location/{}コマンドの一部に注意してください。このコマンドは、前のコマンドで出力された各行に対してビルドおよび実行されます。ここでは、前のコマンドで出力された行が{}の代わりに置き換えられます。
Xargsのmanページからの抜粋:
xargs-標準入力からコマンドラインをビルドおよび実行します
詳細については、manページを参照してください:man xargs
私は通常、他の人が提案したことをします...割り当てなしで:
$find . -iname '*.cpp' -print
./foo.cpp
./bar.cpp
$vi `!!`
2 files to edit
あなたが好きならあなたはより凝ったものを得ることができます:
$grep -R "some variable" * | grep -v tags
./foo/bar/xxx
./bar/foo/yyy
$vi `!!`
最後のコマンドを再実行して出力を取得するだけであれば、単純なbash変数が機能します。
LAST=`!!`
したがって、次のコマンドを使用して出力に対してコマンドを実行できます。
yourCommand $LAST
これにより、新しいプロセスが生成されてコマンドが再実行され、出力が表示されます。本当に欲しいのは、コマンド出力用のbash履歴ファイルになりそうです。これは、bashが端末に送信する出力をキャプチャする必要があることを意味します。必要な/ devまたは/ procを監視するために何かを書くこともできますが、それは面倒です。また、途中でteeコマンドを使用して用語とbashの間に「特別なパイプ」を作成し、出力ファイルにリダイレクトすることもできます。
しかし、これらはどちらもハッキングソリューションの一種です。最高の方法は ターミネータ であると思います。これは、出力ロギングを備えた最新の端末です。最後のコマンドの結果については、ログファイルを確認してください。上記と同様のbash変数を使用すると、さらに簡単になります。
コマンドを実行し、結果を変数に保存することを決定した後に行う方法の1つを次に示します。
$ find . -name foo.txt
./home/user/some/directory/foo.txt
$ OUTPUT=`!!`
$ echo $OUTPUT
./home/user/some/directory/foo.txt
$ mv $OUTPUT somewhere/else/
または、変数に結果が必要であることを事前に知っている場合は、バックティックを使用できます。
$ OUTPUT=`find . -name foo.txt`
$ echo $OUTPUT
./home/user/some/directory/foo.txt
!!:1を使用できます。例:
~]$ ls *.~
class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~
~]$ rm !!:1
rm class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~
~]$ ls file_to_remove1 file_to_remove2
file_to_remove1 file_to_remove2
~]$ rm !!:1
rm file_to_remove1
~]$ rm !!:2
rm file_to_remove2
既存の回答の代替として:ファイル名に次のような空白を含めることができる場合は、while
を使用します。
find . -name foo.txt | while IFS= read -r var; do
echo "$var"
done
私が書いたように、違いはファイル名に空白が必要な場合にのみ関係します。
NB:唯一の組み込みのものは、出力に関するものではなく、最後のコマンドのステータスに関するものです。
同様のニーズがあり、最後のコマンドの出力を次のコマンドに使用したかった。のような| (パイプ)。例えば
$ which gradle
/usr/bin/gradle
$ ls -alrt /usr/bin/gradle
のようなものに-
$ which gradle |: ls -altr {}
解決策:このカスタムパイプを作成しました。 xargsを使用して、本当に簡単に-
$ alias :='xargs -I{}'
基本的にxargsのショートハンドを作成しても何もありません。魅力のように機能し、本当に便利です。 .bash_profileファイルにエイリアスを追加するだけです。
ファイル記述子の魔法とlastpipe
Shellオプションを使用して実行できます。
スクリプトを使用して行う必要があります-「lastpipe」オプションは対話モードでは機能しません。
私がテストしたスクリプトは次のとおりです。
$ cat shorttest.sh
#!/bin/bash
shopt -s lastpipe
exit_tests() {
EXITMSG="$(cat /proc/self/fd/0)"
}
ls /bloop 2>&1 | exit_tests
echo "My output is \"$EXITMSG\""
$ bash shorttest.sh
My output is "ls: cannot access '/bloop': No such file or directory"
ここでやっていることは:
シェルオプションshopt -s lastpipe
を設定します。ファイル記述子が失われるため、これがないと機能しません。
私のstderrも2>&1
でキャプチャされることを確認する
出力を関数にパイプして、stdinファイル記述子を参照できるようにします。
/proc/self/fd/0
ファイル記述子(stdin)の内容を取得して変数を設定します。
スクリプトのエラーをキャプチャするためにこれを使用しているため、コマンドに問題がある場合は、スクリプトの処理を停止してすぐに終了できます。
shopt -s lastpipe
exit_tests() {
MYSTUFF="$(cat /proc/self/fd/0)"
BADLINE=$BASH_LINENO
}
error_msg () {
echo -e "$0: line $BADLINE\n\t $MYSTUFF"
exit 1
}
ls /bloop 2>&1 | exit_tests ; [[ "${PIPESTATUS[0]}" == "0" ]] || error_msg
この方法で、チェックしたいすべてのコマンドの後ろに2>&1 | exit_tests ; [[ "${PIPESTATUS[0]}" == "0" ]] || error_msg
を追加できます。
これで、出力を楽しむことができます!
find . -name foo.txt 1> tmpfile && mv `cat tmpfile` /path/to/some/dir/
汚れているとはいえ、さらに別の方法です。
これは厳密にはbashソリューションではありませんが、sedでパイピングを使用して前のコマンド出力の最後の行を取得できます。
まず、フォルダ「a」にあるものを確認します
rasjani@helruo-dhcp022206::~$ find a
a
a/foo
a/bar
a/bat
a/baz
rasjani@helruo-dhcp022206::~$
次に、lsとcdを使用した例は、sedに変わり、次のようなパイプになります。
rasjani@helruo-dhcp022206::~$ cd `find a |sed '$!d'`
rasjani@helruo-dhcp022206::~/a/baz$ pwd
/home/rasjani/a/baz
rasjani@helruo-dhcp022206::~/a/baz$
したがって、実際の魔法はsedで発生し、これまでのコマンドの出力をsedにパイプして、sedに最後の行を出力し、バックティックのパラメーターとして使用できます。または、それをxargsに結合することもできます。 (シェルの「man xargs」はあなたの友達です)
シェルには、最後のコマンドのエコー結果を保存するPerlのような特別なシンボルはありません。
Awkでパイプシンボルを使用する方法を学びます。
find . | awk '{ print "FILE:" $0 }'
上記の例では、次のことができます。
find . -name "foo.txt" | awk '{ print "mv "$0" ~/bar/" | "sh" }'