Automate VIM EDITOR and update values using shell script (similar to editing crontab via shell script) - vim

I am trying to automate a VI edit for a command similar to crontab editing via Shell script but not working for me so far.
Here is the final json with admin as true:
'{"name":"SQLSRVR","admin":"true","json_class":"Chef::ApiClient","chef_type":"client"}'
As you can see the EDITOR environment variable has to be set or passed as command line option -e
[root#vrhost user]# knife client edit SQLSRVR
ERROR: RuntimeError: Please set EDITOR environment variable
[root#vrhost user]# knife client edit
USAGE: knife client edit CLIENT (options)
-s, --server-url URL Chef Server URL
-k, --key KEY API Client Key
--[no-]color Use colored output, defaults to enabled
-c, --config CONFIG The configuration file to use
--defaults Accept default values for all questions
-d, --disable-editing Do not open EDITOR, just accept the data as is
-e, --editor EDITOR Set the editor to use for interactive commands
-E, --environment ENVIRONMENT Set the Chef environment
-F, --format FORMAT Which format to use for output
-u, --user USER API Client Username
--print-after Show the data after a destructive operation
-V, --verbose More verbose output. Use twice for max verbosity
-v, --version Show chef version
-y, --yes Say yes to all prompts for confirmation
-h, --help Show this message
FATAL: You must specify a client name
The below command opens a vim editor for editing to make the change from ["admin": "false"] to ["admin": "true"]:
[root#vrhost user]# knife client edit SQLSRVR -e vim
{
"name": "SQLSRVR",
"admin": false,
"json_class": "Chef::ApiClient",
"chef_type": "client",
}
I am trying to do this through a shell script and would like to automate it and tried many options but had no luck so far.
[root#vrhost ~]# (echo ^[:g/false/s/false/true/^[:wq!^M) | knife client edit SQLSRVR -e vim
Vim: Warning: Input is not from a terminal
Object unchanged, not saving
or
[root#vrhost user]# echo (^[echo '{"name":"SQLSRVR","admin":"true","json_class":"Chef::ApiClient","chef_type":"client"}'^[:w q!^M) | knife client edit SQLSRVR -e
[root#vrhost ~]# knife client show SQLSRVR
admin: false
chef_type: client
json_class: Chef::ApiClient
name: SQLSRVR
this is very similar to automating crontab editing via shell script but this has not been working for me.

Unless you really need special Vim capabilities, you're probably better off using non-interactive tools like sed, awk, or Perl / Python / Ruby / your favorite scripting language here.
That said, you can use Vim non-interactively, using silent batch mode.
vim -T dumb --noplugin -n -es -S "commands.ex" "filespec"
Instead of the external script to read the commands from via -S "commands.ex", you can also give a few commands directly via -c cmd1 -c cmd2. See :help -s-ex for more information.

Check out
$ knife client edit --help
[...]
-d, --disable-editing Do not open EDITOR, just accept the data as is
So I guess you can change the values without editing in vim. Just:
get the client data in json format.
replace needed values with sed.
upload the data from file.
Code:
$ knife client show -Fj SQLSRVR > SQLSRVR.json
$ sed -i.old "s/\"admin\": true,/\"admin\": false,/" SQLSRVR.json
$ knife client edit -d SQLSRVR < SQLSRVR.json
Something like that.

Here are some links to references:
i) http://mirror.hep.wisc.edu/stable/chef/chef-server-webui/app/controllers/clients_controller.rb
ii) http://www.rubydoc.info/github/opscode/chef/master/Shell/Extensions - tried but unable to get it to work
Finally did the following (it does give 409 the 2nd time on call and I did not need to do it a 2nd time):
# call to below rb, CLIENTNAME is the name of the client and STATE is true/false
$ knife exec clienttransform.rb CLIENTNAME STATE
$ cat clienttransform.rb
Chef::Config[:solo] = false
class Company
class TransformClient
attr_accessor :clientname
attr_accessor :isclientadmin
def initialize(client_name, is_client_admin)
#clientname = client_name
#isclientadmin = is_client_admin
end
def transform
client=Chef::ApiClient.load(#clientname)
# puts "client.name : " + client.name
# puts "client.admin : " + client.admin.to_s
# puts "XX - clientname : " + #clientname
# puts "XX - isclientadmin : " + #isclientadmin.to_s
boolisclientadmin = !!#isclientadmin
client.admin(boolisclientadmin)
client.save()
end
end
end
client_name = ARGV[2].to_s()
is_client_admin = ARGV[3].to_s()
# puts "YY - client_name : " + client_name
# puts "YY - is_client_admin : " + is_client_admin
trc = Company::TransformClient.new(client_name, is_client_admin)
trc.transform
exit 0

Just set your editor and it will work. In my case I use vim editor that's why my command was as follows:
export EDITOR=vim

Related

Where is the config file store for the xfce4-plugin "notification area" alias "systray"

I am on Qubes OS. That means fedora-25 as dom0. I would like to change the configs for "notification area" alias "systray" plugin of xfce. How can I do it. I would like to delete/add one item.
The Gui only gives me the option to hide with ugly arrow on the side or to "clear all known applications". However, regarding the last option I am afraid to lose the notification area as it is and never get it back.
I looked with the "find" command for "xfce4" and "xfce4-plugins" and so on. All the files I could find, e.g. in ~/.config/xfce4, could not help me. I can nowhere find a config file for the plugin.
Thanks in advance :)
Known applications is stored as an array in xfconf, in the xfce4-panel channel and under the property /plugins/plugin-[id]/known-items, where the plugin id is dynamic and depends on the order plugins were added to panel.
You could hack your way messing with ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml but I strongly advise you not to, instead use xfconf-query to read and set values.
I'm going to write down some snippets below so you can use them to craft a script that suits your needs:
# Find the plugin id, can be empty if systray is not present
xfconf-query -c xfce4-panel -p /plugins -l -v | grep systray | grep -Po "plugin-\\d+" | head -n1
# Get array of current known apps
xfconf-query -c xfce4-panel -p /plugins/$PLUGIN_ID/known-items | tail -n +3
# Set array of known apps
xfconf-query -c xfce4-panel -p /plugins/$PLUGIN_ID/known-items -t string -s value1 -t string -s value2 ...

Copy Terminal Output For GUI Pasting [duplicate]

Is it possible to pipe to/from the clipboard in Bash?
Whether it is piping to/from a device handle or using an auxiliary application, I can't find anything.
For example, if /dev/clip was a device linking to the clipboard we could do:
cat /dev/clip # Dump the contents of the clipboard
cat foo > /dev/clip # Dump the contents of "foo" into the clipboard
There are a wealth of clipboards you could be dealing with. I expect you're probably a Linux user who wants to put stuff in the X Windows primary clipboard. Usually, the clipboard you want to talk to has a utility that lets you talk to it.
In the case of X, there's xclip (and others). xclip -selection c will send data to the clipboard that works with Ctrl + C, Ctrl + V in most applications.
If you're on Mac OS X, there's pbcopy. E.g., cat example.txt | pbcopy
If you're in Linux terminal mode (no X) then look into gpm or Screen which has a clipboard. Try the Screen command readreg.
Under Windows 10+ or Cygwin, use /dev/clipboard or clip.
Make sure you are using alias xclip="xclip -selection c"
or else you won't be able to paste using Ctrl+v.
Example:
After running echo -n test | xclip, Ctrl+v will paste test
Install
# You can install xclip using `apt-get`
apt-get install xclip
# or `pacman`
pacman -S xclip
# or `dnf`
dnf install xclip
If you do not have access to apt-get nor pacman, nor dnf, the sources are available on sourceforge.
Set-up
Bash
In ~/.bash_aliases, add:
alias setclip="xclip -selection c"
alias getclip="xclip -selection c -o"
Do not forget to load your new configuration using . ~/.bash_aliases or by restarting your profile.
Fish
In ~/.config/fish/config.fish, add:
abbr setclip "xclip -selection c"
abbr getclip "xclip -selection c -o"
Do not forget to restart your fish instance by restarting your terminal for changes to apply.
Usage
You can now use setclip and getclip, e.g:
$ echo foo | setclip
$ getclip
foo
On macOS, use the built-in pbcopy and pbpaste commands.
For example, if you run
cat ~/.bashrc | pbcopy
the contents of the ~/.bashrc file will be available for pasting with the Cmd + V shortcut.
To save the current clipboard to a file, redirect the output pbpaste to a file:
pbpaste > my_clipboard.txt
2018 answer
Use clipboard-cli. It works with macOS, Windows, Linux, OpenBSD, FreeBSD, and Android without any real issues.
Install it with:
npm install -g clipboard-cli
Then you can do:
echo foo | clipboard
If you want, you can alias to cb by putting the following in your .bashrc, .bash_profile, or .zshrc:
alias cb=clipboard
xsel on Debian/Ubuntu/Mint
# append to clipboard:
cat 'the file with content' | xsel -ab
# or type in the happy face :) and ...
echo 'the happy face :) and content' | xsel -ib
# show clipboard
xsel -ob
# Get more info:
man xsel
Install
sudo apt-get install xsel
Try
xclip
xclip - command line interface to X selections (clipboard)
man
On the Windows Subsystem for Linux (WSL) you can copy to the clipboard with clip.exe:
cat file | clip.exe
Keep in mind to use the | pipe command. And not a > command, since that will not work.
Install the xcopy utility and when you're in the Terminal, input:
Copy
Thing_you_want_to_copy | xclip -selection c
Paste
myvariable=$(xclip -selection clipboard -o)
I noticed a lot of answers recommended pbpaste and pbcopy. If you're into those utilities, but for some reason they are not available in your repository, you can always make an alias for the xcopy commands and call them pbpaste and pbcopy.
alias pbcopy="xclip -selection c"
alias pbpaste="xclip -selection clipboard -o"
So then it would look like this:
Thing_you_want_to_copy | pbcopy
myvariable=$(pbpaste)
An answer located in one of the comments written by a user called doug work for me. Since I found it so helpful, I decided to restate in an answer.
Here is a ready-to-use Bash script for reading the clipboard which works on multiple platforms.
Please edit the script here if you add functionality (e.g., more platforms).
#!/bin/bash
# WF 2013-10-04
#
# Multi-platform clipboard read access
#
# Supports
# Mac OS X
# Git shell / Cygwin (Windows)
# Linux (e.g., Ubuntu)
#
# Display an error
#
error() {
echo "error: $1" 1>&2
exit 1
}
#
# getClipboard
#
function getClipboard() {
os=`uname`
case $os in
# Git Bash (Windows)
MINGW32_NT-6.1)
cat /dev/clipboard;;
# Mac OS X
Darwin*)
pbpaste;;
# Linux
Linux*)
# Works only for the X clipboard - a check that X is running might be due
xclip -o;;
*)
error "unsupported os $os";;
esac
}
tmp=/tmp/clipboard$$
getClipboard >$tmp
cat $tmp
# Comment out for debugging
rm $tmp
For Mac only:
echo "Hello World" | pbcopy
pbpaste
These are located /usr/bin/pbcopy and /usr/bin/pbpaste.
On Windows (with Cygwin) try
cat /dev/clipboard or echo "foo" > /dev/clipboard as mentioned in this article.
There are different clipboards in Linux; the X server has one, the window manager might have another one, etc. There is no standard device.
Oh, yes, on CLI, the screen program has its own clipboard as well, as do some other applications like Emacs and vi.
In X, you can use xclip.
You can check this thread for other possible answers:
http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2004-07/0919.html
This is a simple Python script that does just what you need:
#!/usr/bin/python
import sys
# Clipboard storage
clipboard_file = '/tmp/clipboard.tmp'
if(sys.stdin.isatty()): # Should write clipboard contents out to stdout
with open(clipboard_file, 'r') as c:
sys.stdout.write(c.read())
elif(sys.stdout.isatty()): # Should save stdin to clipboard
with open(clipboard_file, 'w') as c:
c.write(sys.stdin.read())
Save this as an executable somewhere in your path (I saved it to /usr/local/bin/clip. You can pipe in stuff to be saved to your clipboard...
echo "Hello World" | clip
And you can pipe what's in your clipboard to some other program...
clip | cowsay
_____________
< Hello World >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Running it by itself will simply output what's in the clipboard.
I have found a good reference: How to target multiple selections with xclip
In my case, I would like to paste content on the clipboard and also to see what is been pasted there, so I used also the tee command with a file descriptor:
echo "just a test" | tee >(xclip -i -selection clipboard)
>() is a form of process substitution. Bash replaces each with the path to a file descriptor which is connected to the standard input of the program within the parentheses.
The teecommand forks your command allowing you to "pipe its content" and see the result on standard output "stdout".
You can also create aliases to get and write on the clipboard, allowing you to use "pbcopy" and "pbpaste" as if you where on Mac. In my case, as I use Z shell (zsh), I have this in my aliases file:
(( $+commands[xclip] )) && {
alias pbpaste='xclip -i -selection clipboard -o'
alias pbcopy='xclip -selection clipboard'
}
The (( $+command[name] )) in Z shell tests if the command "name" is installed on your system, and then both aliases are grouped with {}. The && is a binary AND; if a then b, hence if you have xclip then the aliases will be set.
echo "another test" | tee >(pbcopy)
To get your clipboard content, just type:
pbpaste | "any-command-you-need-here"
I just searched the same stuff in my KDE environment.
Feel free to use clipcopy and clippaste.
KDE:
> echo "TEST CLIP FROM TERMINAL" | clipcopy
> clippaste
TEST CLIP FROM TERMINAL
xsel -b
Does the job for X Window, and it is mostly already installed.
A look in the man page of xsel is worth the effort.
Copy and paste to clipboard in Windows (Cygwin):
See:
$ clip.exe -?
CLIP
Description:
Redirects output of command line tools to the Windows clipboard.
This text output can then be pasted into other programs.
Parameter List:
/? Displays this help message.
Examples:
DIR | CLIP Places a copy of the current directory
listing into the Windows clipboard.
CLIP < README.TXT Places a copy of the text from readme.txt
on to the Windows clipboard.
Also getclip (it can be used instead of Shift + Ins!) and putclip (echo oaeuoa | putclip.exe to put it into clip) exist.
In Linux this works:
cat filename | xclip
pbcopy is built into OS X:
Copying the content of file .bash_profile:
cat ~/.bash_profile | pbcopy
There are a couple of ways. Some of the ways that have been mentioned include (I think) tmux, Screen, Vim, Emacs, and the shell. I don't know Emacs or Screen, so I'll go over the other three.
Tmux
While not an X selection, tmux has a copy mode accessible via prefix-[ (prefix is Ctrl + B by default). The buffer used for this mode is separate and exclusive to tmux, which opens up quite a few possibilities and makes it more versatile than the X selections in the right situations.
To exit this mode, hit Q; to navigate, use your Vim or Emacs binding (default = Vim), so hjkl for movement, v/V/C-v for character/line/block selection, etc. When you have your selection, hit Enter to copy and exit the mode.
To paste from this buffer, use prefix-].
Shell
Any installation of X11 seems to come with two programs by default: xclip and xsel (kind of like how it also comes with both startx and xinit). Most of the other answers mention xclip, and I really like xsel for its brevity, so I'm going to cover xsel.
From xsel(1x):
Input options \
-a, --append \
append standard input to the selection. Implies -i.
-f, --follow \
append to selection as standard input grows. Implies -i.
-i, --input \
read standard input into the selection.
Output options \
-o, --output \
write the selection to standard output.
Action options \
-c, --clear \
clear the selection. Overrides all input options.
-d, --delete \
Request that the current selection be deleted. This not only clears the selection, but also requests to the program in which the selection resides that the selected contents be deleted. Overrides all input options.
Selection options \
-p, --primary \
operate on the PRIMARY selection (default).
-s, --secondary \
operate on the SECONDARY selection.
-b, --clipboard \
operate on the CLIPBOARD selection.
And that's about all you need to know. p (or nothing) for PRIMARY, s for SECONDARY, b for CLIPBOARD, o for output.
Example: say I want to copy the output of foo from a TTY and paste it to a webpage for a bug report. To do this, it would be ideal to copy to/from the TTY/X session. So the question becomes how do I access the clipboard from the TTY?
For this example, we'll assume the X session is on display :1.
$ foo -v
Error: not a real TTY
details:
blah blah # 0x0000000040abeaf4
blah blah # 0x0000000040abeaf8
blah blah # 0x0000000040abeafc
blah blah # 0x0000000040abeb00
...
$ foo -v | DISPLAY=:1 xsel -b # copies it into clipboard of display :1
Then I can Ctrl + V it into the form as per usual.
Now say that someone on the support site gives me a command to run to fix the problem. It's complicated and long.
$ DISPLAY=:1 xsel -bo
sudo foo --update --clear-cache --source-list="http://foo-software.com/repository/foo/debian/ubuntu/xenial/164914519191464/sources.txt"
$ $(DISPLAY=:1 xsel -bo)
Password for braden:
UPDATING %%%%%%%%%%%%%%%%%%%%%%% 100.00%
Clearing cache...
Fetching sources...
Reticulating splines...
Watering trees...
Climbing mountains...
Looking advanced...
Done.
$ foo
Thank you for your order. A pizza should arrive at your house in the next 20 minutes. Your total is $6.99
Pizza ordering seems like a productive use of the command line.
...moving on.
Vim
If compiled with +clipboard (This is important! Check your vim --version), Vim should have access to the X PRIMARY and CLIPBOARD selections. The two selections are accessible from the * and + registers, respectively, and may be written to and read from at your leisure the same as any other register.
For example:
:%y+ ; copy/yank (y) everything (%) into the CLIPBOARD selection (+)
"+p ; select (") the CLIPBOARD selection (+) and paste/put it
ggVG"+y ; Alternative version of the first example
If your copy of Vim doesn't directly support access to X selections, though, it's not the end of the world. You can just use the xsel technique as described in the last section.
:r ! xsel -bo ; read (r) from the stdout of (!) `xsel -bo`
:w ! xsel -b ; write (w) to the stdin of (!) `xsel -b`
Bind a couple key combos and you should be good.
On Wayland, xcopy doesn't seem to work. Use wl-clipboard instead.
E.g., on Fedora:
sudo dnf install wl-clipboard
tree | wl-copy
wl-paste > file
The Ruby oneliner inspired me to try with Python.
Say we want a command that indents whatever is in the clipboard with four spaces. It is perfect for sharing snippets on Stack Overflow.
$ pbpaste | python -c "import sys
for line in sys.stdin:
print(f' {line}')" | pbcopy
That's not a typo. Python needs newlines to do a for loop. We want to alter the lines in one pass to avoid building up an extra array in memory.
If you don't mind building the extra array try:
$ pbpaste | python -c "import sys; print(''.join([f' {l}' for l in sys.stdin]))" | pbcopy
but honestly awk is better for this than python. I defined this alias in my ~/.bashrc file
alias indent="pbpaste | awk '{print \" \"\$0}' | pbcopy"
Now when I run indent, whatever is in my clipboard is indented.
A few Windows programs I wrote years ago. They allow you dump, push, append and print the clipboard. It works like this:
dumpclip | perl -pe "s/monkey/chimp/g;" | pushclip
It includes source code: cmd_clip.zip
Yesterday I found myself with the question: "How can I share the clipboard between different user sessions?". When switching between sessions with Ctrl + Alt + F7 - Ctrl + Alt + F8, in fact, you can't paste what you copied.
I came up with the following quick & dirty solution, based on a named pipe. It is surely quite bare and raw, but I found it functional:
user1#host:~$ mkfifo /tmp/sharedClip
then in the sending terminal
user1#host:~$ cat > /tmp/sharedClip
last, in the receiving terminal:
user2#host:~$ cat /tmp/sharedClip
Now, you type or paste anything in the first terminal, and (after hitting Return), it will appear immediately in the receiving terminal, from where you can copy and paste again anywhere you like.
Of course this doesn't just strictly take the content from user1's clipboard to make it available in user2's clipboard, but rather it requires an additional pair of Paste & Copy clicks.
From this thread, there is an option which does not require installing any gclip/xclip/xsel third-party software.
A Perl script (since Perl is usually always installed)
use Win32::Clipboard;
print Win32::Clipboard::GetText();
In macOS, use pbpaste.
For example:
Update the clipboard
pbpaste | ruby -ne ' puts "\|" + $_.split( )[1..4].join("\|") ' | pbcopy
A way to paste from the clipboard to a file without any tools except echo.
Escape single quotes in the text you want to paste: replace all occurrences of ' with '\'' and copy the result to clipboard.
Type echo -n '
Press Shift + Insert
Type ' > filename.txt
Press Enter
Basically you're doing this:
echo -n 'copied "text" with '\''single quotes'\'' escaped' > filename.txt
It works even if the copied text has new lines.
For mac you can use this function which uses pbcopy and pbpaste, but a little easier:
Add this to your .bashrc or .zshrc:
clp() {
if [[ -z "$1" ]]
then
# No input - act as paste
pbpaste;
else
# Input exists - act as copy
echo "$1" | pbcopy;
fi
}
To copy use clp "Content" and to paste use clp
If you're like me and run on a Linux server without root privileges and there isn't any xclip or GPM you could workaround this issue by just using a temporary file. For example:
$ echo "Hello, World!" > ~/clip
$ echo `cat ~/clip`
Hello, World!

Problem of running command from Rundeck (Linux)

On a linux server I am running following command with any error and getting the result.
xxxxx#server1 ~]$ grep -o "\-w.*%" /etc/sysconfig/nrpe-disk
-w 15% -c 7%
[xxxxx#server1 ~]$
I want to run same command from Rundeck's command line interface with same xxx user which has sudo rights too.
Command executed from rundeck gives option '.' invalide error:
option invalide -- '.'
Utilisation : grep [OPTION]... MOTIF [FICHIER].
I tried many times with different ways such as escaping . sign, running it with sudo, with absolute path, double quotes - single quotes etc. Still I am receiving same output however, in the server command works locally. What's the way to fix it ?
You can do that putting that on an inline-script ("Script" step) or call an external script with the command content ("Script file or URL" step).
Another way is to use cat tool to print the file and capture the output using log filter (Click on the tiny Gear icon at the left of the step > Click on "Add Log Filter" > Select "Key/value data" and in pattern use with this regex: .*(-w .*%).*, put a name of the data - eg: diskdata - and click on "Log data" checkbox) and you get the output that you want, you can print that value using echo ${data.diskdata} in next step. Check.

Use crontab job send mail, The email text turns to an attached file which named ATT00001.bin

I want to analysis some data in one linux server,then send the it as Email text to my Email account , But when i execute this shell scripts in shell command, It works well, Weird is that when i put all the procedure into crontab job, The Email text will turns to an attached file, Can someone help?
#* * * * * sh -x /opt/bin/exec.sh >> /opt/bin/mailerror 2>&1
/* exec.sh */
#/bin/sh
cd /opt/bin
./analysis.sh > test
mail -s "Today's Weather" example#example.com < test
But when i execute exec.sh in shell command line directly, The Email will get text, Can someone explain it for me, grate thanks.
Ran into the same problem myself, only I'm piping text output into mailx - Heirloom mailx 12.4 7/29/08
When running the script on the command line the email came out as normal email with a text body.
However, when I ran the exact same script via crontab the body of the email came as an attachment - ATT00001.BIN (Outlook), application/octet-stream (mutt) or "noname" (Gmail).
Took some research to figure this out, but here goes:
Problem
Mailx will, if it encounters unknown / control characters in text input, convert it into an attachment with application/octet-stream mime-type set.
From the man page:
for any file that contains formatting characters other than newlines and horizontal tabulators
So you need to remove those control characters, which can be done with i.e. tr
echo "$Output" | /usr/bin/tr -cd '\11\12\15\40-\176' | mail ...
However since I had Norwegian UTF8 characters: æøå - the list expand, and you don't really want to maintain such a list, and I need the norwegian characters.
And inspecting the attachment I found I had only \r, \n the "regular" ASCII characters in range 32-176 - all printable and 184 and 195 --> UTF8
Sollution
Explicitly set the locale in your script:
LANG="en_US.UTF8" ; export LANG
Run export in your shell - or setenv if you run csh or tcsh to determine what your locale is set to.
Explanation
Mailx - when run in your shell - with LANG set to .UTF8, will correctly identify the UTF8 chars and continue.
When run in crontab LANG is not set, and default to LANG=C, since by default crontab will run only a restricted set of environment variables (system dependant).
mailx (or other programs) will then not recognize UTF8 characters and determine that the input containes unknown control characters.
My issue was UTF8 characters, yours could be other control characters in your input. Run it through hexdump or od -c, but since it works OK in a regular shell I'm suspecting LANG issues.
References:
linux mail < file.log has Content-Type: application/octet-stream (a noname attachment in Gmail)
http://alvinalexander.com/blog/post/linux-unix/how-remove-non-printable-ascii-characters-file-unix
I had this same issue and none of the above fixed the problem. Moving the extra return in the file fixed the issue for me:
cat logfile | tr -d \\r | mailx -s'the logfile' to-me#.....
Thanks to this forum:
https://forums.opensuse.org/showthread.php/445955-mailx-creates-unwanted-attachment
Make sure you change this in your script
#/bin/sh
to be replaced by
#!/bin/sh
Coming to the problem
Your script assumes that it is being run from a particular directory (note that almost every path is a relative path, not an absolute path). cron happens to be running it from another directory.
The Fix for text appearing on email
mydir=$(dirname "$0") && cd "${mydir}" || exit 1
./opt/bin/analysis.sh > test
mail -s "Today's Weather" example#example.com < /opt/bin/test
Explanation
$0 is the (possibly relative) filename of the shell script being executed. Given a filename, the dirname command returns the directory containing the filename.
So, that line changes directories to the directory containing the script or exits with an error code if either dirname or cd fails.
OR try to have full path like
./opt/bin/analysis.sh > test
mail -s "Today's Weather" example#example.com < /opt/bin/test
Note: The same problem is discussed earlier here
FOLLOW UP:
Try to remove
sh -x /opt/bin/exec.sh >> /opt/bin/mailerror 2>&1
and instead use
sh /opt/bin/exec.sh 2>&1 >> /opt/bin/mailerror
FOLLOW UP
You have to restart cron for changes to take effect if you do not use the crontab command to edit the file.
crontab -l > oldcrontab
cp oldcrontab newcrontab
echo "$newline" >> newcrontab
crontab < newcrontab
In my case, the cron was not a shell script but a PHP script (so I couldn't put the export LANG thing):
0 9 * * * apache php /test/myscript.php | mail -s "CRON - myscript" foo#bar.com
Solution:
In order to fix the same issue (content is mailed as attachment instead of body), I add LANG=fr_FR.UTF-8 at the beginning of the cron file:
MAILTO=vme1.etc-crond-backoffice-conf
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
LANG=fr_FR.UTF-8
0 9 * * * apache php /test/myscript.php | mail -s "CRON - myscript" foo#bar.com
NB: puting LANG=fr_FR.UTF-8 in the /etc/environment file and restarting cron service worked too.
Reference:
Set LANG in crontab https://www.logikdev.com/2010/02/02/locale-settings-for-your-cron-job/

Pipe to/from the clipboard in a Bash script

Is it possible to pipe to/from the clipboard in Bash?
Whether it is piping to/from a device handle or using an auxiliary application, I can't find anything.
For example, if /dev/clip was a device linking to the clipboard we could do:
cat /dev/clip # Dump the contents of the clipboard
cat foo > /dev/clip # Dump the contents of "foo" into the clipboard
There are a wealth of clipboards you could be dealing with. I expect you're probably a Linux user who wants to put stuff in the X Windows primary clipboard. Usually, the clipboard you want to talk to has a utility that lets you talk to it.
In the case of X, there's xclip (and others). xclip -selection c will send data to the clipboard that works with Ctrl + C, Ctrl + V in most applications.
If you're on Mac OS X, there's pbcopy. E.g., cat example.txt | pbcopy
If you're in Linux terminal mode (no X) then look into gpm or Screen which has a clipboard. Try the Screen command readreg.
Under Windows 10+ or Cygwin, use /dev/clipboard or clip.
Make sure you are using alias xclip="xclip -selection c"
or else you won't be able to paste using Ctrl+v.
Example:
After running echo -n test | xclip, Ctrl+v will paste test
Install
# You can install xclip using `apt-get`
apt-get install xclip
# or `pacman`
pacman -S xclip
# or `dnf`
dnf install xclip
If you do not have access to apt-get nor pacman, nor dnf, the sources are available on sourceforge.
Set-up
Bash
In ~/.bash_aliases, add:
alias setclip="xclip -selection c"
alias getclip="xclip -selection c -o"
Do not forget to load your new configuration using . ~/.bash_aliases or by restarting your profile.
Fish
In ~/.config/fish/config.fish, add:
abbr setclip "xclip -selection c"
abbr getclip "xclip -selection c -o"
Do not forget to restart your fish instance by restarting your terminal for changes to apply.
Usage
You can now use setclip and getclip, e.g:
$ echo foo | setclip
$ getclip
foo
On macOS, use the built-in pbcopy and pbpaste commands.
For example, if you run
cat ~/.bashrc | pbcopy
the contents of the ~/.bashrc file will be available for pasting with the Cmd + V shortcut.
To save the current clipboard to a file, redirect the output pbpaste to a file:
pbpaste > my_clipboard.txt
2018 answer
Use clipboard-cli. It works with macOS, Windows, Linux, OpenBSD, FreeBSD, and Android without any real issues.
Install it with:
npm install -g clipboard-cli
Then you can do:
echo foo | clipboard
If you want, you can alias to cb by putting the following in your .bashrc, .bash_profile, or .zshrc:
alias cb=clipboard
xsel on Debian/Ubuntu/Mint
# append to clipboard:
cat 'the file with content' | xsel -ab
# or type in the happy face :) and ...
echo 'the happy face :) and content' | xsel -ib
# show clipboard
xsel -ob
# Get more info:
man xsel
Install
sudo apt-get install xsel
Try
xclip
xclip - command line interface to X selections (clipboard)
man
On the Windows Subsystem for Linux (WSL) you can copy to the clipboard with clip.exe:
cat file | clip.exe
Keep in mind to use the | pipe command. And not a > command, since that will not work.
Install the xcopy utility and when you're in the Terminal, input:
Copy
Thing_you_want_to_copy | xclip -selection c
Paste
myvariable=$(xclip -selection clipboard -o)
I noticed a lot of answers recommended pbpaste and pbcopy. If you're into those utilities, but for some reason they are not available in your repository, you can always make an alias for the xcopy commands and call them pbpaste and pbcopy.
alias pbcopy="xclip -selection c"
alias pbpaste="xclip -selection clipboard -o"
So then it would look like this:
Thing_you_want_to_copy | pbcopy
myvariable=$(pbpaste)
An answer located in one of the comments written by a user called doug work for me. Since I found it so helpful, I decided to restate in an answer.
Here is a ready-to-use Bash script for reading the clipboard which works on multiple platforms.
Please edit the script here if you add functionality (e.g., more platforms).
#!/bin/bash
# WF 2013-10-04
#
# Multi-platform clipboard read access
#
# Supports
# Mac OS X
# Git shell / Cygwin (Windows)
# Linux (e.g., Ubuntu)
#
# Display an error
#
error() {
echo "error: $1" 1>&2
exit 1
}
#
# getClipboard
#
function getClipboard() {
os=`uname`
case $os in
# Git Bash (Windows)
MINGW32_NT-6.1)
cat /dev/clipboard;;
# Mac OS X
Darwin*)
pbpaste;;
# Linux
Linux*)
# Works only for the X clipboard - a check that X is running might be due
xclip -o;;
*)
error "unsupported os $os";;
esac
}
tmp=/tmp/clipboard$$
getClipboard >$tmp
cat $tmp
# Comment out for debugging
rm $tmp
For Mac only:
echo "Hello World" | pbcopy
pbpaste
These are located /usr/bin/pbcopy and /usr/bin/pbpaste.
On Windows (with Cygwin) try
cat /dev/clipboard or echo "foo" > /dev/clipboard as mentioned in this article.
There are different clipboards in Linux; the X server has one, the window manager might have another one, etc. There is no standard device.
Oh, yes, on CLI, the screen program has its own clipboard as well, as do some other applications like Emacs and vi.
In X, you can use xclip.
You can check this thread for other possible answers:
http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2004-07/0919.html
This is a simple Python script that does just what you need:
#!/usr/bin/python
import sys
# Clipboard storage
clipboard_file = '/tmp/clipboard.tmp'
if(sys.stdin.isatty()): # Should write clipboard contents out to stdout
with open(clipboard_file, 'r') as c:
sys.stdout.write(c.read())
elif(sys.stdout.isatty()): # Should save stdin to clipboard
with open(clipboard_file, 'w') as c:
c.write(sys.stdin.read())
Save this as an executable somewhere in your path (I saved it to /usr/local/bin/clip. You can pipe in stuff to be saved to your clipboard...
echo "Hello World" | clip
And you can pipe what's in your clipboard to some other program...
clip | cowsay
_____________
< Hello World >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Running it by itself will simply output what's in the clipboard.
I have found a good reference: How to target multiple selections with xclip
In my case, I would like to paste content on the clipboard and also to see what is been pasted there, so I used also the tee command with a file descriptor:
echo "just a test" | tee >(xclip -i -selection clipboard)
>() is a form of process substitution. Bash replaces each with the path to a file descriptor which is connected to the standard input of the program within the parentheses.
The teecommand forks your command allowing you to "pipe its content" and see the result on standard output "stdout".
You can also create aliases to get and write on the clipboard, allowing you to use "pbcopy" and "pbpaste" as if you where on Mac. In my case, as I use Z shell (zsh), I have this in my aliases file:
(( $+commands[xclip] )) && {
alias pbpaste='xclip -i -selection clipboard -o'
alias pbcopy='xclip -selection clipboard'
}
The (( $+command[name] )) in Z shell tests if the command "name" is installed on your system, and then both aliases are grouped with {}. The && is a binary AND; if a then b, hence if you have xclip then the aliases will be set.
echo "another test" | tee >(pbcopy)
To get your clipboard content, just type:
pbpaste | "any-command-you-need-here"
I just searched the same stuff in my KDE environment.
Feel free to use clipcopy and clippaste.
KDE:
> echo "TEST CLIP FROM TERMINAL" | clipcopy
> clippaste
TEST CLIP FROM TERMINAL
xsel -b
Does the job for X Window, and it is mostly already installed.
A look in the man page of xsel is worth the effort.
Copy and paste to clipboard in Windows (Cygwin):
See:
$ clip.exe -?
CLIP
Description:
Redirects output of command line tools to the Windows clipboard.
This text output can then be pasted into other programs.
Parameter List:
/? Displays this help message.
Examples:
DIR | CLIP Places a copy of the current directory
listing into the Windows clipboard.
CLIP < README.TXT Places a copy of the text from readme.txt
on to the Windows clipboard.
Also getclip (it can be used instead of Shift + Ins!) and putclip (echo oaeuoa | putclip.exe to put it into clip) exist.
In Linux this works:
cat filename | xclip
pbcopy is built into OS X:
Copying the content of file .bash_profile:
cat ~/.bash_profile | pbcopy
There are a couple of ways. Some of the ways that have been mentioned include (I think) tmux, Screen, Vim, Emacs, and the shell. I don't know Emacs or Screen, so I'll go over the other three.
Tmux
While not an X selection, tmux has a copy mode accessible via prefix-[ (prefix is Ctrl + B by default). The buffer used for this mode is separate and exclusive to tmux, which opens up quite a few possibilities and makes it more versatile than the X selections in the right situations.
To exit this mode, hit Q; to navigate, use your Vim or Emacs binding (default = Vim), so hjkl for movement, v/V/C-v for character/line/block selection, etc. When you have your selection, hit Enter to copy and exit the mode.
To paste from this buffer, use prefix-].
Shell
Any installation of X11 seems to come with two programs by default: xclip and xsel (kind of like how it also comes with both startx and xinit). Most of the other answers mention xclip, and I really like xsel for its brevity, so I'm going to cover xsel.
From xsel(1x):
Input options \
-a, --append \
append standard input to the selection. Implies -i.
-f, --follow \
append to selection as standard input grows. Implies -i.
-i, --input \
read standard input into the selection.
Output options \
-o, --output \
write the selection to standard output.
Action options \
-c, --clear \
clear the selection. Overrides all input options.
-d, --delete \
Request that the current selection be deleted. This not only clears the selection, but also requests to the program in which the selection resides that the selected contents be deleted. Overrides all input options.
Selection options \
-p, --primary \
operate on the PRIMARY selection (default).
-s, --secondary \
operate on the SECONDARY selection.
-b, --clipboard \
operate on the CLIPBOARD selection.
And that's about all you need to know. p (or nothing) for PRIMARY, s for SECONDARY, b for CLIPBOARD, o for output.
Example: say I want to copy the output of foo from a TTY and paste it to a webpage for a bug report. To do this, it would be ideal to copy to/from the TTY/X session. So the question becomes how do I access the clipboard from the TTY?
For this example, we'll assume the X session is on display :1.
$ foo -v
Error: not a real TTY
details:
blah blah # 0x0000000040abeaf4
blah blah # 0x0000000040abeaf8
blah blah # 0x0000000040abeafc
blah blah # 0x0000000040abeb00
...
$ foo -v | DISPLAY=:1 xsel -b # copies it into clipboard of display :1
Then I can Ctrl + V it into the form as per usual.
Now say that someone on the support site gives me a command to run to fix the problem. It's complicated and long.
$ DISPLAY=:1 xsel -bo
sudo foo --update --clear-cache --source-list="http://foo-software.com/repository/foo/debian/ubuntu/xenial/164914519191464/sources.txt"
$ $(DISPLAY=:1 xsel -bo)
Password for braden:
UPDATING %%%%%%%%%%%%%%%%%%%%%%% 100.00%
Clearing cache...
Fetching sources...
Reticulating splines...
Watering trees...
Climbing mountains...
Looking advanced...
Done.
$ foo
Thank you for your order. A pizza should arrive at your house in the next 20 minutes. Your total is $6.99
Pizza ordering seems like a productive use of the command line.
...moving on.
Vim
If compiled with +clipboard (This is important! Check your vim --version), Vim should have access to the X PRIMARY and CLIPBOARD selections. The two selections are accessible from the * and + registers, respectively, and may be written to and read from at your leisure the same as any other register.
For example:
:%y+ ; copy/yank (y) everything (%) into the CLIPBOARD selection (+)
"+p ; select (") the CLIPBOARD selection (+) and paste/put it
ggVG"+y ; Alternative version of the first example
If your copy of Vim doesn't directly support access to X selections, though, it's not the end of the world. You can just use the xsel technique as described in the last section.
:r ! xsel -bo ; read (r) from the stdout of (!) `xsel -bo`
:w ! xsel -b ; write (w) to the stdin of (!) `xsel -b`
Bind a couple key combos and you should be good.
On Wayland, xcopy doesn't seem to work. Use wl-clipboard instead.
E.g., on Fedora:
sudo dnf install wl-clipboard
tree | wl-copy
wl-paste > file
The Ruby oneliner inspired me to try with Python.
Say we want a command that indents whatever is in the clipboard with four spaces. It is perfect for sharing snippets on Stack Overflow.
$ pbpaste | python -c "import sys
for line in sys.stdin:
print(f' {line}')" | pbcopy
That's not a typo. Python needs newlines to do a for loop. We want to alter the lines in one pass to avoid building up an extra array in memory.
If you don't mind building the extra array try:
$ pbpaste | python -c "import sys; print(''.join([f' {l}' for l in sys.stdin]))" | pbcopy
but honestly awk is better for this than python. I defined this alias in my ~/.bashrc file
alias indent="pbpaste | awk '{print \" \"\$0}' | pbcopy"
Now when I run indent, whatever is in my clipboard is indented.
A few Windows programs I wrote years ago. They allow you dump, push, append and print the clipboard. It works like this:
dumpclip | perl -pe "s/monkey/chimp/g;" | pushclip
It includes source code: cmd_clip.zip
Yesterday I found myself with the question: "How can I share the clipboard between different user sessions?". When switching between sessions with Ctrl + Alt + F7 - Ctrl + Alt + F8, in fact, you can't paste what you copied.
I came up with the following quick & dirty solution, based on a named pipe. It is surely quite bare and raw, but I found it functional:
user1#host:~$ mkfifo /tmp/sharedClip
then in the sending terminal
user1#host:~$ cat > /tmp/sharedClip
last, in the receiving terminal:
user2#host:~$ cat /tmp/sharedClip
Now, you type or paste anything in the first terminal, and (after hitting Return), it will appear immediately in the receiving terminal, from where you can copy and paste again anywhere you like.
Of course this doesn't just strictly take the content from user1's clipboard to make it available in user2's clipboard, but rather it requires an additional pair of Paste & Copy clicks.
From this thread, there is an option which does not require installing any gclip/xclip/xsel third-party software.
A Perl script (since Perl is usually always installed)
use Win32::Clipboard;
print Win32::Clipboard::GetText();
In macOS, use pbpaste.
For example:
Update the clipboard
pbpaste | ruby -ne ' puts "\|" + $_.split( )[1..4].join("\|") ' | pbcopy
A way to paste from the clipboard to a file without any tools except echo.
Escape single quotes in the text you want to paste: replace all occurrences of ' with '\'' and copy the result to clipboard.
Type echo -n '
Press Shift + Insert
Type ' > filename.txt
Press Enter
Basically you're doing this:
echo -n 'copied "text" with '\''single quotes'\'' escaped' > filename.txt
It works even if the copied text has new lines.
For mac you can use this function which uses pbcopy and pbpaste, but a little easier:
Add this to your .bashrc or .zshrc:
clp() {
if [[ -z "$1" ]]
then
# No input - act as paste
pbpaste;
else
# Input exists - act as copy
echo "$1" | pbcopy;
fi
}
To copy use clp "Content" and to paste use clp
If you're like me and run on a Linux server without root privileges and there isn't any xclip or GPM you could workaround this issue by just using a temporary file. For example:
$ echo "Hello, World!" > ~/clip
$ echo `cat ~/clip`
Hello, World!

Resources