bashを呼び出し、新しいシェル内でコマンドを実行してから、ユーザーに制御を戻す方法は?


86

これは本当に単純か本当に複雑である必要がありますが、それについて何も見つかりませんでした...新しいbashインスタンスを開いて、その中でいくつかのコマンドを実行し、その中のユーザーに制御を戻そうとしています。同じインスタンス

私は試した:

$ bash -lic "some_command"

ただし、これはsome_command新しいインスタンス内で実行されてから閉じます。開いたままにしておきたい。

回答に影響を与える可能性のあるもう1つの詳細:これを機能させることができれば.bashrc、エイリアスとして使用するので、alias実装のボーナスポイントになります!


エイリアスについての最後の部分がわかりません。エイリアスは現在のシェルのコンテキストで実行されるため、解決を求めている問題は発生しません(ただし、通常、さまざまな理由から、関数はエイリアスよりも優れています)。
トリプリー2011

2
alias shortcut='bash -lic "some_command"'.bashrcに次のようなものを入れて実行しshortcutsome_commandすでに実行されている新しいシェルを作成できるようにしたいです。
フェリックスSaparelli

回答:


65
bash --rcfile <(echo '. ~/.bashrc; some_command')

一時ファイルの作成を省略します。他のサイトでの質問:


私はWindows10でこれを実行しようとしました(バッチの「スタートアップ」ファイル/スクリプトを書き込もうとしました)、そして私は得ますThe system cannot find the file specified.
Doctor Blue

1
@Scottはそれを段階的にデバッグします:1)cat ~/.bashrc動作しますか?2)cat <(echo a)動作しますか?3)bash --rcfile somefile動作しますか?
CiroSantilli郝海东冠状病六四事件法轮功2017

1
@Scott WSLでこの問題が発生しました(起動バッチファイルからbashを起動します)。私たちの解決策は、バッチがそれを理解できるようにいくつかの文字をエスケープすることでした:bash.exe --rcfile ^<^(echo 'source $HOME/.bashrc; ls; pwd'^)Windowsコマンドプロンプトから実行する必要があります。
user2561747 2017

sudo bash --init-file <(echo "ls; pwd")またはなどのユーザー切り替えで機能させる方法はありsudo -iu username bash --init-file <(echo "ls; pwd")ますか?
jeremysprofile


40

これは遅い答えですが、私はまったく同じ問題を抱えていて、Googleが私をこのページに送ったので、完全を期すために、ここで問題を回避する方法を説明します。

私の知る限りbash、元のポスターがやりたかったことをするオプションはありません。この-cオプションは、コマンドが実行された後は常に戻ります。

壊れた解決策:これを回避する最も簡単で明白な試みは次のとおりです。

bash -c 'XXXX ; bash'

これは部分的に機能します(追加のサブシェルレイヤーがありますが)。ただし、問題は、サブシェルがエクスポートされた環境変数を継承する一方で、エイリアスと関数が継承されないことです。したがって、これはいくつかの点で機能する可能性がありますが、一般的な解決策ではありません。

より良い方法:これを回避する方法は、スタートアップファイルを動的に作成し、この新しい初期化ファイルでbashを呼び出し、~/.bashrc必要に応じて新しいinitファイルが通常のファイルを呼び出すようにすることです。

# Create a temporary file
TMPFILE=$(mktemp)

# Add stuff to the temporary file
echo "source ~/.bashrc" > $TMPFILE
echo "<other commands>" >> $TMPFILE
echo "rm -f $TMPFILE" >> $TMPFILE

# Start the new bash shell 
bash --rcfile $TMPFILE

良い点は、一時的なinitファイルが使用されるとすぐにそれ自体を削除し、正しくクリーンアップされないリスクを軽減することです。

注:/ etc / bashrcが通常の非ログインシェルの一部として通常呼び出されるかどうかはわかりません。もしそうなら、あなたは/ etc / bashrcとあなたのを調達したいかもしれません~/.bashrc


rm -f $TMPFILEことは、それを作ります。私は実際にこれのユースケースを覚えていません、そして今私はより高度な自動化技術を使用しています、しかしこれは行く方法です!
フェリックスSaparelli

8
プロセス置換のあるtmpファイルはありませんbash --rcfile <(echo ". ~/.bashrc; a=b")
CiroSantilli郝海东冠事病六四事件法轮功2014

3
一時ファイルは、Bashスクリプトが正常に実行された場合にのみクリーンアップされます。より堅牢なソリューションは、を使用することtrapです。
トリプリー2016

5

--rcfileBashに渡して、選択したファイルを読み取らせることができます。このファイルは、の代わりに読み取られます.bashrc。(それが問題である場合は、ソース~/.bashrcは、他のスクリプトから入手してください。)

編集:それで、もので新しいシェルを開始する関数~/.more.shは次のようになります:

more() { bash --rcfile ~/.more.sh ; }

...そして.more.sh、シェルの起動時に実行したいコマンドがあります。(個別のスタートアップファイルを避けるのが賢明だと思います。シェルがインタラクティブにならないため、標準入力を使用できませんが、ヒアドキュメントから一時的な場所にスタートアップファイルを作成して読み取ることができます。)


3

スクリプトを実行する代わりにソースを使用することで、必要な機能を取得できます。例えば:

$ catスクリプト
cmd1
cmd2
$。脚本
$この時点で、cmd1とcmd2はこのシェル内で実行されています

うーん。それは機能しますが、すべてをに埋め込む方法はありませんalias=''か?
フェリックスSaparelli

1
エイリアスは絶対に使用しないでください。代わりに関数を使用してください。次のように入力できます: 'foo(){cmd1; cmd2; } '起動スクリプト内で、fooを実行すると、現在のシェルで2つのコマンドが実行されます。これらのソリューションはどちらも新しいシェルを提供しないことに注意してください。ただし、「
execbash

1
絶対とは絶対言うな。エイリアスにはその場所があります
glenn jackman 2011

エイリアスの代わりに関数を使用できないユースケースの例はありますか?
William Pursell 2011

3

次の~/.bashrcようなセクションに追加します。

if [ "$subshell" = 'true' ]
then
    # commands to execute only on a subshell
    date
fi
alias sub='subshell=true bash'

次に、でサブシェルを開始できますsub


オリジナリティのポイント。エイリアス自体は、おそらくより良いようであるenv subshell=true bash(それが漏れないよう$subshell、後続のコマンドに):ENV使用輸出を使用します
フェリックスSaparelli

あなたが正しいです。しかし、私はそれがなくenvても機能することに気づきました。が定義されているかどうかを確認するために、echo $subshell(使用する代わりにenv | grep subshell)使用します。
dashohoxha 2015

3

受け入れられた答えは本当に役に立ちます!そのプロセス置換(つまり、<(COMMAND))を追加するだけでは、一部のシェル(たとえば、dash)ではサポートされていません。

私の場合、Thunarファイルマネージャーでカスタムアクション(基本的には1行のシェルスクリプト)を作成して、シェルを起動し、選択したPython仮想環境をアクティブ化しようとしていました。私の最初の試みは:

urxvt -e bash --rcfile <(echo ". $HOME/.bashrc; . %f/bin/activate;")

%fThunarが処理する仮想環境へのパスはどこにありますか。(コマンドラインからThunarを実行して)エラーが発生しました:

/bin/sh: 1: Syntax error: "(" unexpected

それから、私のsh(本質的にdash)はプロセス置換をサポートしていないことに気づきました。

私の解決策はbash、追加レベルのシェルを犠牲にして、プロセス置換を解釈するためにトップレベルで呼び出すことでした。

bash -c 'urxvt -e bash --rcfile <(echo "source $HOME/.bashrc; source %f/bin/activate;")'

または、ヒアドキュメントを使用しようとしましdashたが、成功しませんでした。何かのようなもの:

echo -e " <<EOF\n. $HOME/.bashrc; . %f/bin/activate;\nEOF\n" | xargs -0 urxvt -e bash --rcfile

PS:コメントを投稿するのに十分な評判がありません。モデレーターは、コメントに移動するか、この質問に役立たない場合は削除してください。


bashを上に置きたくない(または持っていない)場合は、プロセス置換を直接実装するためのさまざまな文書化された方法があります。ほとんどの場合、FIFOを使用します。
フェリックスSaparelli

2

daverajaの回答に従って、目的を解決するbashスクリプトを次に示します。

Cシェルを使用している場合の状況を考慮してくださいていて、次のようにCシェルのコンテキスト/ウィンドウを離れずにコマンドを実行するます。

実行するコマンド*。h、*。cファイルでのみ現在のディレクトリで正確な単語「Testing」を再帰的に検索します

grep -nrs --color -w --include="*.{h,c}" Testing ./

解決策1:Cシェルからbashに入り、コマンドを実行します

bash
grep -nrs --color -w --include="*.{h,c}" Testing ./
exit

解決策2:目的のコマンドをテキストファイルに書き込み、bashを使用して実行します

echo 'grep -nrs --color -w --include="*.{h,c}" Testing ./' > tmp_file.txt
bash tmp_file.txt

解決策3:bashを使用して同じ行でコマンドを実行する

bash -c 'grep -nrs --color -w --include="*.{h,c}" Testing ./'

解決策4:sciprtを(1回)作成し、それを今後のすべてのコマンドに使用する

alias ebash './execute_command_on_bash.sh'
ebash grep -nrs --color -w --include="*.{h,c}" Testing ./

スクリプトは次のとおりです。

#!/bin/bash
# =========================================================================
# References:
# https://stackoverflow.com/a/13343457/5409274
# https://stackoverflow.com/a/26733366/5409274
# https://stackoverflow.com/a/2853811/5409274
# https://stackoverflow.com/a/2853811/5409274
# https://www.linuxquestions.org/questions/other-%2Anix-55/how-can-i-run-a-command-on-another-shell-without-changing-the-current-shell-794580/
# https://www.tldp.org/LDP/abs/html/internalvariables.html
# https://stackoverflow.com/a/4277753/5409274
# =========================================================================

# Enable following line to see the script commands
# getting printing along with their execution. This will help for debugging.
#set -o verbose

E_BADARGS=85

if [ ! -n "$1" ]
then
  echo "Usage: `basename $0` grep -nrs --color -w --include=\"*.{h,c}\" Testing ."
  echo "Usage: `basename $0` find . -name \"*.txt\""
  exit $E_BADARGS
fi  

# Create a temporary file
TMPFILE=$(mktemp)

# Add stuff to the temporary file
#echo "echo Hello World...." >> $TMPFILE

#initialize the variable that will contain the whole argument string
argList=""
#iterate on each argument
for arg in "$@"
do
  #if an argument contains a white space, enclose it in double quotes and append to the list
  #otherwise simply append the argument to the list
  if echo $arg | grep -q " "; then
   argList="$argList \"$arg\""
  else
   argList="$argList $arg"
  fi
done

#remove a possible trailing space at the beginning of the list
argList=$(echo $argList | sed 's/^ *//')

# Echoing the command to be executed to tmp file
echo "$argList" >> $TMPFILE

# Note: This should be your last command
# Important last command which deletes the tmp file
last_command="rm -f $TMPFILE"
echo "$last_command" >> $TMPFILE

#echo "---------------------------------------------"
#echo "TMPFILE is $TMPFILE as follows"
#cat $TMPFILE
#echo "---------------------------------------------"

check_for_last_line=$(tail -n 1 $TMPFILE | grep -o "$last_command")
#echo $check_for_last_line

#if tail -n 1 $TMPFILE | grep -o "$last_command"
if [ "$check_for_last_line" == "$last_command" ]
then
  #echo "Okay..."
  bash $TMPFILE
  exit 0
else
  echo "Something is wrong"
  echo "Last command in your tmp file should be removing itself"
  echo "Aborting the process"
  exit 1
fi

2
これは、まったく異なる問題に対するまったく異なる答えです。(あなたがそれを理解したのはクールですが、それはこのスレッドに属していません。これがこのサイトに存在しなかった場合は、2番目の文で新しい質問を開き、すぐに残りの部分で自分で答えることを検討してください...これを処理する方法です☺)一時ファイルをまったく作成せずにそれを行う方法については、CiroSantilliの回答も参照してください。
フェリックスSaparelli

この質問に答える試みではないため、回答なしのフラグが立てられます(ただし、別の質問に答えるのは非常にすばらしい試みです!)
CharlesDuffy20年

0
$ bash --init-file <(echo 'some_command')
$ bash --rcfile <(echo 'some_command')

プロセス置換を使用できない、または使用したくない場合:

$ cat script
some_command
$ bash --init-file script

別の方法:

$ bash -c 'some_command; exec bash'
$ sh -c 'some_command; exec sh'

sh-唯一の方法(dashbusybox):

$ ENV=script sh

良い代替案ですがENV=script、トップアンサーの露骨なコピーアンドペーストと混同されないように、トップセクション(パーツの前)を削除または言い換えることでメリットが得られます。
フェリックスSaparelli

@FélixSaparelli率直に言って、ENV+以外のすべての解決策shは他の回答に存在しますが、ほとんどの場合、大量のテキストに埋もれているか、不要な/不要なコードに囲まれています。簡潔で明確な要約を持つことは、すべての人にとって有益であると私は信じています。
X-ゆり

0

これがさらに別の(機能する)バリアントです:

これにより、新しいgnomeターミナルが開き、新しいターミナルでbashが実行されます。ユーザーのrcファイルが最初に読み取られ、次にコマンドls -laが実行のために新しいシェルに送信されてから、インタラクティブになります。最後のエコーは、実行を終了するために必要な改行を追加します。

gnome-terminal -- bash -c 'bash --rcfile <( cat ~/.bashrc; echo ls -la ; echo)'

また、端末を装飾することも便利な場合があります。

gnome-terminal --profile green -- bash -c 'bash --rcfile <( cat ~/.bashrc; echo ls -la ; echo)'

-1

バックグラウンドシェルでコマンドを実行する

&コマンドの最後に追加するだけです。例:

bash -c some_command && another_command &
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.