Run same command on all terminals in mac - macos

Is there a way to run the same command on all the open terminal tabs . I usually log into many servers and want to perform the same command on all of them. Xshell (available on windows only) had this feature where you can run same command on all open terminals , i am wondering if its possible in mac somehow ?

It is most definitely possible. I do it quite often. This solves it:
onall () {
if [[ $1 == "--help" ]]; then
echo "Usage: onall <command>"
return 0
fi
osascript -e "tell application \"Terminal\"
repeat with w in windows
repeat with t in tabs of w
do script \"${1//\"/\\\"}\" in t
end repeat
end repeat
end tell"
}
osascript is the command-line program to run AppleScript code and the -e option tells it to use the following string as the script. The ${1//\"/\\\"} escapes all of the quotes in the command.
You can either declare it as is in your .bash_profile or whatever other file you use or you can take it out of the function, put it into a script, make the script executable and put it somewhere that is always in your PATH.
NOTE 1: The entire command must be in the first argument.
NOTE 2: If you're doing a command with quotes in it, you must escape the quotes.
For example, onall echo "*" will not give the expected results. Instead, use onall "echo \"*\""

iTerm2 can solve this problem.
steps:
split terminal as per your requirement
click on shell -> broadcast input (select broadcast setting as per you requirement)
Screen shot for reference:

Instead of using Terminal for this, use SSH. If it's a command you need to run in a terminal, odds are you're sshing somewhere anyway - eliminate the middle man.
Generate passwordless ssh keypair, put the public key on the remote systems, then from a single shell script you can do something like
for host in host1 host2 host3 ..; do
ssh -i ~/.ssh/my_private_key username#${host} "echo HAXXXXXXXXXXXX | wall"
done
This is a very crude mechanism, but it's lightyears beyond having to physically open a terminal for each command.
I actually know of something that'll do what you want on OSX, but honestly it's such a generically bad idea it would be negligent of me to provide a hyperlink to it.

Related

Is there any way to come back to a ready-to-enter command in fish shell by just pressing a combination of keys?

Some times that I have a command ready to press enter but that command I have changed it in some way and it's a long command, then I remember that I have to open a text file (e.g. to get some information that I will use in the command). So what most of the times I do, is to cancel that command (Ctrl+C) and then open the text file get the information I need and then retype the command again with the pasted value from the text file. This is not very efficient for me specially if the server doesn't have any kind of GUI and I can't copy the previous command so I don't lose it.
So my question is, Is there any kind of combination keys that I could use to save a command ready to enter so I don't lose it and I don't have to type it all over again?
Thanks!
This is currently not possible out of the box.
The easiest way to do it is probably to
Change the cancel binding to stash the commandline
Add a binding to recall the stashed commandline
It would work something like this:
The function to recall:
function recall_commandline
if set -q stashed_commandline
commandline -r -- $stashed_commandline
end
end
Add to __fish_cancel_commandline (use funced __fish_cancel_commandline. Once you are happy do funcsave __fish_cancel_commandline):
set -g stashed_commandline $cmd
# right before:
commandline ""
Add to fish_user_key_bindings
bind \cr recall_commandline
This will allow you to press Ctrl+r to recall the last cancelled commandline. Expanding it to multiple is non-trivial (since "commandlines" can have multiple lines), as is adding the commandlines to history so that they can be recalled with the normal bindings.
I have the following function to turn comment/uncomment the current statement:
function toggle-comment-cmd-buffer --description 'Comment/Uncomment the current or every line'
set -l cmdlines (commandline -b)
if test "$cmdlines" = ""
return
end
set -l cmdlines (printf '%s\n' '#'$cmdlines | string replace -r '^##' '')
commandline -r $cmdlines
string match -q '#*' $cmdlines[1]; and commandline -f execute
end
I bind it thusly: bind \e\# toggle-comment-cmd-buffer. This way I can quickly comment and put the current statement in my command history in order to do something else. Then I can recall the comment and press [alt-#] again to remove the comment characters and continue modifying the command.
I set this up in my personal fish config because I had gotten used to doing something similar in ksh93.

Execute a shell command on a file selected in the Finder

I'm a very novice and infrequent applescript experimenter. I've tried for several hours now to learn the individual applescript commands for the following task, but I always run into errors. Perhaps someone much more adept at applescript will find this task easy and quick, and for that I would be very grateful. Here is the task:
I want to be able to manually select a document or file within the finder and then execute the following unix command on that file. I would then store the script under Finder's "Services" menu. The unix command is:
srm -rfv -m path/filename
In my attempts, I assumed that a script that would open Terminal and execute the command would be the way to go, but just couldn't get anything to work. Thank you in advance to any good programmers who can whip out such a script for me.
My tip: Create such services using Automator!
Create a new Service in Automator
Choose "File & Folder" as Input and "Finder"
Add "Run shell script"
Choose "as arguments" as input
Change echo "$f" to your command srm -rfv -m "$f"
Save it as "Safe delete"
From now on, if you select a file inside Finder you will find the option "Safe delete" in the context menu.
Enjoy, Michael / Hamburg
Craig's comment is pertinent, but I am just focus on the script itself, not on the shell command. the script bellow must be saved as Application and each time you drop 1 or more file on its icon, the shell script command will be executed for each file :
on open myFiles
repeat with aFile in myFiles -- repeat loop in case you drop more than 1 file on the icon script
try
do shell script "srm -rfv -m " & (quoted form of POSIX path of aFile)
end try
end repeat
end open
Still make sure that in your shell command 'srm -rfv', the 'v' is necessary because this script will not display any thing ! I don't think so. also I did not display error during remove. what do you want to do with error (like write protect, ...) ?
Update: I missed that the OP wants to create an OS X Service that integrates with Finder. ShooTerKo's answer shows how to do that (and his solution doesn't even require use of AppleScript).
The only potentially interesting thing about this answer is that it demonstrates AppleScript commands to open a file-selection dialog, get the chosen file's POSIX path and run a shell command with it, with some general background information about executing shell commands with do shell script.
Try the following:
# Let the user choose a file via an interactive dialog.
set fileChosen to choose file
# Get the file's POSIX path.
set filePath to POSIX path of fileChosen
# Use the path to synthesize a shell command and execute it.
do shell script "echo srm -rfv -m " & quoted form of filePath
Note:
There's no explicit error handling; if you don't want the script to just fail, you'll have to add error handling (try ... on error ... end try) to handle the case of the user canceling the file selection and the shell command failing (unlikely in this case).
The shell command has echo prepended to it in order to perform a dry run (see its output in Script Editor's Result pane); remove it to perform the actual deletion.
quoted form of is important for ensuring that a string value is included as-is in a shell command (no risk of expansion (interpretation) by the shell).
do shell script will NOT open a Terminal window - it will simply run the shell command hidden and return its stdout output, which is usually what you want. If the shell command signals failure via a non-zero exit code, an error is raised.

can the shell be told to save command output?

I'm thinking a hypothetical CMDOUTPUT would be useful:
locate -r 'regexp...' # locate finds a file: /myfile.
# Shell puts `/myfile' string into CMDOUTPUT
vim $CMDOUTPUT # No need to run locate again as with: vim `!!`
The locate command above is just an example. I want the output saved for all commands that I run so that if I need it I can access it quickly. (The output should still be printed by the command to stdout.) I don't want to do
CMDOUTPUT="$(...)"
or
command | tee /tmp/cmdoutput
or anything else that I have to do because that's more typing for me at the prompt for everything that I run: I want the shell to do it all in the background. Again, to make it clear: I am casually typing commands away and decide "Oh, I want to use the output of that last command in this command, let me just retrieve it...". Can I tell the shell to store the output somehow so that I can retrieve it.
If there's no option for it, is there some way that I can implement it that is as close to invisible as it can be, meaning exit codes from the command are not lost (...and that's all I can think of, but I'm sure there are other subtleties) etc. I'm primarily thinking of zsh, but answers for any shell would be useful.
I found a solution, not sure if this is exactly what you're looking for. But it should provide a start :)
zsh | tee log >&1

Simple shell script doesn't work like command line?

I'm trying to write a script that contains this
screen -S demo -d -m which should start a new screen session named demo and detach it.
Putting screen -S demo -d -m in the command line works.
If I put it in a file named boot.sh, and run it ./boot.sh I get
Error: Unknown option m
Why does this work in the command line but not as a shell script?
This file was transferred from windows and had ctrl-M characters.
Running "screen" on my Linux machine, a bad option (Screen version 4.00.03jw4 (FAU) 2-May-06) gives the error,
Error: Unknown option -z"
while your description includes no dash before the offending option. I'd check that the characters in your script file are what you expect them to be. There are many characters that look like a dash but which are not.
cat -v boot.sh
may show something interesting as it'll show codes for non-ascii characters.
This may seem a little like the "make sure your printer is plugged in" kind of help, but anyway:
have you tried to check if the screen you're invoking from the script is the same as the one invoked from the command line ?
I'm thinking you may change the PATH variable inside your script somewhere and perhaps screen from the script would be something else (a different version, perhaps ?).

Making a command loop in shell with a script

How can one loop a command/program in a Unix shell without writing the loop into a script or other application.
For example, I wrote a script that outputs a light sensor value but I'm still testing it right now so I want it run it in a loop by running the executable repeatedly.
Maybe I'd also like to just run "ls" or "df" in a loop. I know I can do this easily in a few lines of bash code, but being able to type a command in the terminal for any given set of command would be just as useful to me.
You can write the exact same loop you would write in a shell script by writing it in one line putting semicolons instead of returns, like in
for NAME [in LIST ]; do COMMANDS; done
At that point you could write a shell script called, for example, repeat that, given a command, runs it N times, by simpling changing COMMANDS with $1 .
I recommend the use of "watch", it just do exactly what you want, and it cleans the terminal before each execution of the commands, so it's easy to monitor changes.
You probably have it already, just try watch ls or watch ./my_script.sh. You can even control how much time to wait between each execution, in seconds, with the -n option, and you can use -d to highlight the difference in the output of consecutive runs.
Try:
Run ls each second:
watch -n 1 ls
Run my_script.sh each 3 seconds, and highlight differences:
watch -n 3 -d ./my_script.sh
watch program man page:
http://linux.die.net/man/1/watch
This doesn't exactly answer your question, but I felt it was relavent. One of the great things with shell looping is that some commands return lists of items. Of course that is obvious, but a something you can do using the for loop is execute a command on that list of items.
for $file in `find . -name *.wma`; do cp $file ./new/location/ done;
You can get creative and do some very powerful stuff.
Aside from accepting arguments, anything you can do in a script can be done on the command line. Earlier I typed this directly in to bash to watch a directory fill up as I transferred files:
while sleep 5s
do
ls photos
end

Resources