UNIX sort: Sorting something from the clipboard - linux

The other day I saw a colleague of mine using sort to sort a number of lines he copied from a text file.
I've been trying to reproduce it myself and I cannot seem to find how.
The requirements are as follow:
Use sort from command line, plus whatever else you need to add to configure input
Paste the text to be sorted from the clipboard
Get the sorted result in the console

If you type sort - the command will accept input from stdin. Then you can just paste whatever you want into the console and type CTRL-D to sort it.

Easy, just type sort (or sort -) to run on stdin, paste your lines, and hit CTRL+D for end-of-transmission to sort.

Use xclip.
xclip -o | sort -

I did something like:
xclip -o | sort > /tmp/xclip_temp; xclip -i < /tmp/xclip_temp;cat /tmp/xclip_temp; rm /tmp/xclip_temp
It does:
Stores the sorted input from the clipboard in the /tmp/xclip_temp file;
Puts the sorted input from the file back to the clipboard;
Prints the sorted value on the console;
And finally deletes the temp file;
The reason I am using ; instead of | is because pipe works as a parallel process, so if I used just | I would be overwriting the value of xclip while it was still being read.
For your convenience, you can add a function in your ~/.bashrc file, like this:
sort_xclip()
{
xclip -o | sort > /tmp/xclip_temp; xclip -i < /tmp/xclip_temp; cat /tmp/xclip_temp; rm /tmp/xclip_temp;
}
So you can just type sort_xclip when you want to do it again.
PS: After you edit the ~/.bashrc, run source ~/.bashrc, then the terminal will loads the function you just created.

Related

How to create a dynamic command in bash?

I want to have a command in a variable that runs a program and specifies the output filename for it depending on the number of files exits (to work on a new file each time).
Here is what I have:
export MY_COMMAND="myprogram -o ./dir/outfile-0.txt"
However I would like to make this outfile number increases each time MY_COMMAND is being executed. You may suppose myprogram creates the file soon enough before the next call. So the number can be retrieved from the number of files exists in the directory ./dir/. I do not have access to change myprogram itself or the use of MY_COMMAND.
Thanks in advance.
Given that you can't change myprogram — its -o option will always write to the file given on the command line, and assuming that something also out of your control is running MY_COMMAND so you can't change the way that MY_COMMAND gets called, you still have control of MY_COMMAND
For the rest of this answer I'm going to change the name MY_COMMAND to callprog mostly because it's easier to type.
You can define callprog as a variable as in your example export callprog="myprogram -o ./dir/outfile-0.txt", but you could instead write a shell script and name that callprog, and a shell script can do pretty much anything you want.
So, you have a directory full of outfile-<num>.txt files and you want to output to the next non-colliding outfile-<num+1>.txt.
Your shell script can get the numbers by listing the files, cutting out only the numbers, sorting them, then take the highest number.
If we have these files in dir:
outfile-0.txt
outfile-1.txt
outfile-5.txt
outfile-10.txt
ls -1 ./dir/outfile*.txt produces the list
./dir/outfile-0.txt
./dir/outfile-1.txt
./dir/outfile-10.txt
./dir/outfile-5.txt
(using outfile and .txt means this will work even if there are other files not name outfile)
Scrape out the number by piping it through the stream editor sed … capture the number and keep only that part:
ls -1 ./dir/outfile*.txt | sed -e 's:^.*dir/outfile-\([0-9][0-9]*\)\.txt$:\1:'
(I'm using colon : instead of the standard slash / so I don't have to escape the directory separator in dir/outfile)
Now you just need to pick the highest number. Sort the numbers and take the top
| sort -rn | head -1
Sorting with -n is numeric, not lexigraphic sorting, -r reverses so the highest number will be first, not last.
Putting it all together, this will list the files, edit the names keeping only the numeric part, sort, and get just the first entry. You want to assign that to a variable to work with it, so it is:
high=$(ls -1 ./dir/outfile*.txt | sed -e 's:^.*dir/outfile-\([0-9][0-9]*\)\.txt$:\1:' | sort -rn | head -1)
In the shell (I'm using bash) you can do math on that, $[high + 1] so if high is 10, the expression produces 11
You would use that as the numeric part of your filename.
The whole shell script then just needs to use that number in the filename. Here it is, with lines broken for better readability:
#!/bin/sh
high=$(ls -1 ./dir/outfile*.txt \
| sed -e 's:^.*dir/outfile-\([0-9][0-9]*\)\.txt$:\1:' \
| sort -rn | head -1)
echo "myprogram -o ./dir/outfile-$[high + 1].txt"
Of course you wouldn't echo myprogram, you'd just run it.
you could do this in a bash function under your .bashrc by using wc to get the number of files in the dir and then adding 1 to the result
yourfunction () {
dir=/path/to/dir
filenum=$(expr $(ls $dir | wc -w) + 1)
myprogram -o $dir/outfile-${filenum}.txt
}
this should get the number of files in $dir and append 1 to that number to get the number you need for the filename. if you place it in your .bashrc or under .bash_aliases and source .bashrc then it should work like any other shell command
You can try exporting a function for MY_COMMAND to run.
next_outfile () {
my_program -o ./dir/outfile-${_next_number}.txt
((_next_number ++ ))
}
export -f next_outfile
export MY_COMMAND="next_outfile" _next_number=0
This relies on a "private" global variable _next_number being initialized to 0 and not otherwise modified.

bash when inside screen, output is truncated if does not fit in a line

Outside screen -
[j#firedesire rb]$ diff -bu root_es-US.pres root_es-MX.pres | sed -n "s/^-\([^=]*\)=.*/'\1'/p" | tr "\\n" ","
'IMG.HEAD.LOGO.URL','LNK.COPYRIGHT.URL','LNK.FOOTSECURITY.URL','LNK.HEADHELP.URL','LNK.HEADYAHOO.URL','LNK.PRIVACY.URL','LNK.TOS.URL','STR.HEAD.LOGO.HEIGHT','STR.HEAD.LOGO.WIDTH','REG.TOS.MAIL.URL','UPGRADE.STR.AGREE.STATEMENT',[j#firedesire rb]$
Inside screen -
[j#firedesire rb]$ diff -bu root_es-US.pres root_es-MX.pres | sed -n "s/^-\([^=]*\)=.*/'\1'/p" | tr "\\n" ","
'IMG.HEAD.LOGO.URL','LNK.COPYRIGHT.URL','LNK.FOOTSECURITY.URL','LNK.HEADHELP.URL','LNK.HEADYAHOO.URL','LNK.PRIVACY.URL','LNK.TOS.URL','STR.HEAD.LOGO.HEIGHT','STR.HEAD.LOGO.WIDTH','REG.TOS.MAIL.URL','UPGR
It gets cut off at 'UPGR where line ends. What could be causing this problem, how can I fix this ?
Your output is wider than your screen
You can force the output to wrap by piping it through less -+S, you'll have to use your arrow keys to view all of the output.
There's an option in screen to toggle wrapping on or off; you may have luck with that as well: https://www.gnu.org/software/screen/manual/html_node/Wrap.html
Another method besides less is to pipe it through cat:
ps aux | cat
top | cat
That won't pause at every screenful, like less or more would do, but when programs would otherwise halt until it receives user input, when they detect that their output is being piped to another process, they just dump out the results and keep going.
I use this a lot with external diff programs attached to my git or svn flags: git diff | cat keeps feeding my diff program all the extra files after the first one, while git diff by itself doesn't.

Paste a chunk of text from stdin to a specific location in a file

I'm trying to figure out how to efficiently copy-paste from X application to the terminal. Specifically I want to highlight a text section in my web browser, then paste this commented to a file after the shebang line.
the code I have so far is this:
xclip -o | sed 's/^/#/' | sed '2n' myscript.pl
the first command takes the text that I have highlighted in my browser
the second command comments the lines by adding #
the last bit does not work..
what I am trying to do here is append the text after line number 2 to my script. But obviously I am doing this wrong.. Does anyone have a helpful suggestion?
You can use sed read for safely handling all types of input, including input with special characters and multiple lines. This requires an intermediate file:
xclip -o | sed -e 's/^/#/g' -e '$s/$/\n/' > TMP && sed -i '1r TMP' den && rm TMP
sed only operates on one input stream (either a pipe or a file), if you are using the output of xclip as the data stream then you can't also tell sed to read from a file. Instead you could use command substitution to store the modified output, and use that in a separate command. How about:
sed "2i$(xclip -o | sed 's/^/#/')" myscript.pl
This will print the amended file to stdout, if you want to edit the file itself then use the -i flag.

Bash standard output display and redirection at the same time

In terminal, sometimes I would like to display the standard output and also save it as a backup. but if I use redirection ( > &> etc), it does not display the output in the terminal anymore.
I think I can do for example ls > localbackup.txt | cat localbackup.txt. But it just doesn't feel right. Is there any shortcut to achieve this?
Thank you!
tee is the command you are looking for:
ls | tee localbackup.txt
In addition to using tee to duplicate the output (and it's worth mentioning that tee is able to append to the file instead of overwriting it, by using tee -a, so that you can run several commands in sequence and retain all of the output), you can also use tail -f to "follow" the output file from a parallel process (e.g. a separate terminal):
command1 >localbackup.txt # create output file
command2 >>localbackup.txt # append to output
and from a separate terminal, at the same time:
tail -f localbackup.txt # this will keep outputting as text is appended to the file

search with in Data displayed as a result of tail Operation?

I am working on a Java EE application where its logs will be generated inside a Linux server .
I have used the command tail -f -n -10000 MyLog
It displayed last 1000 lines from that log file .
Now I pressed Ctrl + c in Putty to disconnect the logs updation ( as i am feared it may be updated with new requests and I will loose my data )
In the displayed result, how can I search for a particular keyword ?? (Used / String name to search but it's not working)
Pipe your output to PAGER.
tail -f -n LINE_CNT LOG_FILE | less
then you can use
/SEARCH_STRING
Two ways:
tail -n 10000 MyLog| grep -i "search phrase"
tail -f -n 10000 MyLog | less
The 2nd method will allow you to search with /. It will only search down but you can press g to go back to the top.
Edit: On testing it seems method 2 doesn't work all that well... if you hit the end of the file it will freeze till you ctrl+c the tail command.
You need to redirect the output from tail into a search utility (e.g. grep). You could do this in two steps: save the output to a file, then search in the file; or in one go: pipe the ouput to the search utility
To see what goes into the file (so you can hit Ctlr+c) you can use the tee command, which duplicates the output to the screen and to a file:
tail -f -n -10000 MyLog | tee <filename>
Then search within the file.
If you want to pipe the result into the search utility, you can use the same trick as above, but use your search program instead of tee
Controlling terminal output on the fly
While running any command in a terminal such as Putty you can use CTRL-S and CTRL-Q to stop and start output to the Putty terminal.
Excluding lines using grep
If you want to exclude lines that contain a specific pattern use grep -v the following would remove all line that contain the string INFO
tail -f logfile | grep -v INFO
Show lines that do not contain the words INFO or DEBUG
tail -f logfile | grep -v -E 'INFO|DEBUG'
Finally, the MOTHER AND FATHER of all tailing tools is xtail.pl
If you have perl on your host xtail.pl is a very nice tool to learn and in a nutshell you can use it to tail multiple files. Very handy.
You can just open it with less command
less logfile_name
when you open the file you can use this guide here
Tip: I suggest, first to use G to go to the end of the file and then to you use Backward Search

Resources