walker's code blog

coder, reader

我最常用的几个Xcode快捷键

⌘(command) ⏎(return) ⌥(option/alt) ⇧(shift) ⌃(control/ctrl)

快速打开文件 ⌘ + ⇧ + O(字母)
快速搜索文本 ⌘ + ⇧ + F
分栏显示 ⌘ + ⌥ + ⏎
退出分栏显示 ⌘ + ⏎
让文件在分栏的右侧显示 ⌥ + click
显示出浮层选择打开位置
导航中点击文件 ⇧ + ⌥ + click
编辑区域中点击文件名 ⇧ + ⌥ + ⌘ + click
隐藏/显示左侧导航区 ⌘ + 0(数字)
隐藏/显示右侧功能区 ⌘ + ⌥ + 0(数字)
隐藏/显示下方调试区 ⌘ + ⇧ + Y
打开/关闭自动补全 Esc
快速类/方法提示 ⌥ + click
自动缩进 ⌃ + I(字母i)
导航中标签页的选择 ⌘ + (1...6)
编辑区文件的选择 ⌃ + (1...5)
跳转到方法 ⌃ + 6
编译 ⌘ + B
编译并运行 ⌘ + R
清理项目 ⌘ + ⇧ + K
中止任务(编译/清理) ⌘ + .

把GAE程序通过SSH部署到VPS

大部分在文档上都写了, 写这篇文章的目的是发现现在appcfg.py update xxxx的时候会打开浏览器访问google请求授权(后台内建了一个本地server, 端口是8090, 授权成功后会带授权码请求本地的8090端口, 所以我们在 ssh 环境中是没有浏览器的, 该怎么解决呢?

我玩 linux 不多, 就以我的知识量这么解决:

  1. 碰到需要访问网站的时候, 程序已经给出了提示, 要你退出, 你当然不退出, 而是把网址复制出来, 在本地打开, 授权成功后, 本地浏览器会请求127.0.0.1:8090, 当然, 什么都不会发生, 但从地址栏里把地址复制到剪贴板.
  2. 回到SSH, 把当前任务放到后台(ctrl+z)
  3. curl访问剪贴板里的地址
  4. 继续ctrl+zcurl请求放到后台
  5. jobs命令查一下, 如果后台没有别的任务的话, appcfg任务的id 应该是1, curl任务id 应该是2(现在以我的1和2为准)
  6. appcfg提到前台: fg %1
  7. 你会看到程序顺利进行下去了
  8. 继续, fg %2把 curl 任务提到前台, 你会看到提示, 什么授权成功之类的

演示:

root@walker:~/KindleEar# appcfg.py update app.yaml module-worker.yaml
07:52 AM Host: appengine.google.com
07:52 AM Application: kindleearwalker; version: 1
07:52 AM Starting update of app: kindleearwalker, version: 1
07:52 AM Getting current resource limits.
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?scope=演示数据
    # step1: 请复制此网址, 并忽略要你退出换电脑的提示

If your browser is on a different machine then exit and re-run this
application with the command-line parameter

  --noauth_local_webserver

# step2: 现在开始把任务放到后台
^Z
[1]+  Stopped                 appcfg.py update app.yaml module-worker.yaml
# step3: 把从本机浏览器复制的回调 url 访问一下
root@walker:~/KindleEar# curl http://localhost:8090/?code=4/CYdQFQLiLBFwa7ajsU1acb1Xx9Kpal6SxMuPIS-dRYo#
# step4: 把访问任务放到后台
^Z
[2]+  Stopped                 curl http://localhost:8090/?code=4/CYdQFQLiLBFwa7ajsU1acb1Xx9Kpal6SxMuPIS-dRYo#
# step 5: 查看一下任务和 ID
root@walker:~/KindleEar# jobs
[1]-  Stopped                 appcfg.py update app.yaml module-worker.yaml
[2]+  Stopped                 curl http://localhost:8090/?code=4/xxxxx#
# step 6: 把appcgf的任务提到前台
root@walker:~/KindleEar# fg %1
appcfg.py update app.yaml module-worker.yaml
Authentication successful.
07:54 AM Scanning files on local disk.
07:54 AM Cloning 15 static files.
07:54 AM Cloning 387 application files.
07:54 AM Uploading 3 files and blobs.
07:54 AM Uploaded 3 files and blobs.
.........省略
07:54 AM Compilation completed.
07:54 AM Starting deployment.
07:54 AM Checking if deployment succeeded.
07:54 AM Deployment successful.
07:54 AM Checking if updated app version is serving.
07:54 AM Completed update of app: kindleearwalker, module: worker, version: 1
# step 7: see? 成功了, 看看剩下的任务吧
root@walker:~/KindleEar# jobs
[2]+  Stopped                 curl http://localhost:8090/?code=4/xxxxxxx#
# step 8: 提到前台来结束吧
root@walker:~/KindleEar# fg %2
curl http://localhost:8090/?code=4/CYdQFQLiLBFwa7ajsU1acb1Xx9Kpal6SxMuPIS-dRYo#
<html><head><title>Authentication Status</title></head><body><p>The authentication flow has completed.</p></body></html>root@walker:~/KindleEar#

-bin-bash和-bin-sh的区别

[该文不严谨, 文末有补充]

脚本test.sh内容:

#!/bin/sh
source pcy.sh #pcy.sh并不存在
echo hello

执行./test.sh,屏幕输出为:

./test.sh: line 2: pcy.sh: No such file or directory

由此可见,在#!/bin/sh的情况下,source不成功,不会运行source后面的代码。 修改test.sh脚本的第一行,变为#!/bin/bash,再次执行./test.sh,屏幕输出为:

./test.sh: line 2: pcy.sh: No such file or directory
hello

由此可见,在#!/bin/bash的情况下,虽然source不成功,但是还是运行了source后面的echo语句。 但是紧接着我又试着运行了一下sh ./test.sh,这次屏幕输出为:

./test.sh: line 2: pcy.sh: No such file or directory

表示虽然脚本中指定了#!/bin/bash,但是如果使用sh 方式运行,如果source不成功,也不会运行source后面的代码。

为什么会有这样的区别呢?

junru同学作了解释

  1. sh一般设成bash的软链
[work@zjm-testing-app46 cy]$ ll /bin/sh
lrwxrwxrwx 1 root root 4 Nov 13 2006 /bin/sh -> bash
  1. 在一般的linux系统当中(如redhat),使用sh调用执行脚本相当于打开了bash的POSIX标准模式
  2. 也就是说 /bin/sh 相当于 /bin/bash --posix

所以,sh跟bash的区别,实际上就是bash有没有开启posix模式的区别

so,可以预想的是,如果第一行写成 #!/bin/bash --posix,那么脚本执行效果跟#!/bin/sh是一样的(遵循posix的特定规范,有可能就包括这样的规范:“当某行代码出错时,不继续往下解释”)

来源: http://www.cnblogs.com/baizhantang/archive/2012/09/11/2680453.html

其它解释

等等, 这里就完了吗? 这里有更明确的说法

CentOS里,/bin/sh是一个指向/bin/bash的符号链接: (只是在 CentOS 里哦)

[root@centosraw ~]# ls -l /bin/*sh
-rwxr-xr-x. 1 root root 903272 Feb 22 05:09 /bin/bash
-rwxr-xr-x. 1 root root 106216 Oct 17  2012 /bin/dash
lrwxrwxrwx. 1 root root      4 Mar 22 10:22 /bin/sh -> bash

但在Mac OS上不是,/bin/sh和/bin/bash是两个不同的文件,尽管它们的大小只相差100字节左右:

iMac:~ wuxiao$ ls -l /bin/*sh
-r-xr-xr-x  1 root  wheel  1371648  6 Nov 16:52 /bin/bash
-rwxr-xr-x  2 root  wheel   772992  6 Nov 16:52 /bin/csh
-r-xr-xr-x  1 root  wheel  2180736  6 Nov 16:52 /bin/ksh
-r-xr-xr-x  1 root  wheel  1371712  6 Nov 16:52 /bin/sh
-rwxr-xr-x  2 root  wheel   772992  6 Nov 16:52 /bin/tcsh
-rwxr-xr-x  1 root  wheel  1103984  6 Nov 16:52 /bin/zsh

来源: https://github.com/qinjx/30min_guides/blob/master/shell.md