clipboard in terminal(copy/paste)

Was watching a CD video with Semaphore and saw the guy in the video manipulating clipboard with pipe directly in the terminal. Pretty cool! Did some research on that.


In Mac, it is pretty straightforward with the built in pbcopy and pbpaste. (pasteboard copy / paste). Some examples:

cat | pbcopy

pbpaste >

ps aux | grep myKeyWord | pbcopy

pbcopy < file.txt

pbpaste | grep myKeyWord


Take Ubuntu as example here. We can install a 16 kB program called xclip:

sudo apt-get install -y xclip

Then we can set alias so we can do the above operation like in osx. If you use bash then set your ~/.bashrc:

alias pbcopy='xclip -selection clipboard'
alias pbpaste='xclip -selection clipboard -o'

If you are like me using fish as main shell, then similarly add below to your ~/.config/fish/ file.

alias pbcopy "xclip -selection clipboard"
alias pbpaste "xclip -selection clipboard -o"

OSX auto cleanup tmp ignore dir

Was putting some project related configs into the OS X /tmp directory, but found it was deleted. Turns out OS X has system scheduled cleanup job for the tmp dir. The config is under ‘/etc/defaults/periodic.conf‘.

I was first trying to leverage the provided ‘daily_clean_tmps_ignore’ parameter to exclude my directory but found not working, have to go to the source shell script to see why. The cleanup script locates in : ‘/etc/periodic/daily/110.clean-tmps’ which will go to the ‘/tmp’ dir and find command to get all the files that are 3 days old(atime, mtime, ctime) and not in the ignore list. So all the names we specified in the ‘daily_clean_tmps_ignore’ will be prefix the ‘! -name $pattern’ so that the $pattern could be excluded. However what i am trying to achieve here is for a directory and all its sub-files/dirs where using the -name is not enough.

We can use the -path option but we cannot add that thru configuration file.

Finally i decided to change the system script to achieve the ignoring by add a -name $pattern -prune option. After modification, it becomes:

 rc=$(for dir in $daily_clean_tmps_dirs
                    [ ."${dir#/}" != ."$dir" -a -d $dir ] && cd $dir && {
                        find -dx . -name 'MyDir' -prune -fstype local -type f $args -delete $print
                        find -dx . -name 'MyDir' -prune -fstype local ! -name . -type d $dargs -delete $print
                    } | sed "s,^\\.,  $dir,"
                done | tee /dev/stderr | wc -l)
            [ -z "$print" ] && rc=0
            [ $rc -gt 1 ] && rc=1
            set -f glob

A SO reference about -prune.

Install jdk 8 in Yosemite 10.10.2

While i was trying to downgrade JDK from 1.8.0._25 to 1.8.0_05 into the yosemite 10.10.2 so that i could use the DCEVM in my OSX.


I first remove the new version by just do a

sudo mv jdk1.8.0_25.jdk ~/Desktop/

Next step is to install the 1.8.0_05 which is the current latest version that DCEVM supports.However, I got the following error:

Your system has Mac OS X Version 10.10.2. This product can be installed on Version 10.7.3 or later.
Visit for more information. 

Logically it looks really weird since apparently 10.10.2 is later than the 10.7.3. I think what they do is just compare the first digit so 1<7.

To install this, I have to spoof the OSX version.

1. go to  /System/Library/CoreServices and find the SystemVersion.plist which from its name we know contains the system version.

2. if you try to edit it directly you will find it r–r–r– readonly. To change it, you can either chmod it to 777 and modify content, or open it with some textEditor and do save as the same file name and extension. Then copy it back to the directory.

3. You can modify the version number to 9001 which is obviously larger than 10.10.1. I suggest you modify both ProductVersion and ProductUserVisibleVersion so that you could go to the “about this Mac” to verify the change.

4. Now you should be able to install without that error.

5. Do remember to change it back to whatever version you were before the modification.


.profile vs .bash_profile in OSX

According to the manual page that ships with OS X:

… it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.

in summary: .profile works with sh or bash. However .bash_profile is bash-specific and will override .profile if present.

mac OS X environment checks .bash_profile, .bash_login, .profile in this order. It will run whichever is the highest in the hierarchy, so, if you have .bash_profile, it will not check .profile.

upgrade java version in OSX

To find the right value that JAVA_HOME should be set to.

1. first executed a `which java` in the nearest Terminal. this told me that /usr/bin/java was the executable that launched the VM.

2. A quick `ls -l /usr/bin/java` told me that it wasn’t a symbolic link to the JDK installation that I was hoping for. Instead, it is a short shell script that executes:
in the terminal, it’ll return /usr/bin/java. (which in turn points to /System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java, which is Apple’s 1.6 version).

3. So, if you want to use the new java version, replace the /usr/bin/java symlink so that it points to /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java instead.

4. The command could be:

sudo ln -fs /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java /usr/bin/java

5.Sanity check your version:

java -version


add indicator for UIwebview loading in iOS

To achieve this,

we need to do several steps:

1. make self as the webview delegate : UIWebViewDelegate.

2. add a UIActivityIndicatorView into the view

3. implement methods like start load in the UIWebViewDelegate;

Below are the details.

 1. make self as the webview delegate : UIWebViewDelegate.

in the .h file, add <UIWebViewDelegate> after the UIViewController.  for example :

@interface VideoSearchViewController : UIViewController<UIWebViewDelegate>

in the .m file. add yourWebView.delegate = self; This step is important, otherwise the delegate methods won’t be called.

2. add a UIActivityIndicatorView into the view

in the storyboard, drag a “UIActivityIndicator” to the center of your webview and set the property Hides when stopped.

create outlet for it: hold control and drag it to the .h file, then name it. This will create something like:

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatior;

add synthesiize for the “activityIndicatior” in the .m file.

3. implement methods for UIWebViewDelegate;

implement below methods:


#pragma spinner
- (void)webViewDidStartLoad:(UIWebView *)searchWebView {

    [ activityIndicatior startAnimating];

- (void)webView:(UIWebView *)searchWebView didFailLoadWithError:(NSError *)error {

    [activityIndicatior stopAnimating];


- (void)webViewDidFinishLoad:(UIWebView *)searchWebView {

    [activityIndicatior stopAnimating];
    activityIndicatior.hidden = YES;

create manual segue and config in viewController

regular segue from storyborad

In StoryBoard we can easily create segue by control drag the source widget to the destination widget.

Then in the viewContoller, just create a method:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"theSegueNameInStoryBoard"]) {
        NSIndexPath *indexPath = [self.searchTableView indexPathForSelectedRow];
        DestinationViewController *destViewController = segue.destinationViewController;
        NSString *parameterToPass= "@someparam";
        destViewController.param = parameterToPass;

if the source widget is a cell in table view, use the indexPath to get the param from context.

if there is some simple condition to determine whether the segue to trigger or not, use:

-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
        return YES;
        return NO;

Manual segue

if the requirement contains determine the Yes or no in a alert, then the previous way will not work since it won’t wait for the user click and trigger the segue immediately.

Then we need to create segue ourselves:



A popup will show for “Manual Segue”. I picked Push as the type. Tap on the little square and make sure you’re in the attributes inspector. Give it an identifier which you will use to refer to it in code.

Next in the button action or table row selected action, we define the actual behavior:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    [self closeDrawer];

    Reachability *reachability = [Reachability reachabilityForInternetConnection];
    [reachability startNotifier];
    NetworkStatus status = [reachability currentReachabilityStatus];
    switch (status) {
        case NotReachable:
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"没有网络连接"
            [alert show];
        case ReachableViaWWAN:
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"没有连接WIFI"
                                                  otherButtonTitles:@"继续", nil];
            [alert show];
        case ReachableViaWiFi:
            [self performSegueWithIdentifier:@"theSegueNameInStoryBoard" sender:self];


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if(buttonIndex != alertView.cancelButtonIndex){
        [self performSegueWithIdentifier:@"theSegueNameInStoryBoard" sender:self];

More detail can be found here.