使用 rbenv 来管理多个版本 ruby

python 的版本管理有 pyenv,同样的 ruby 也有 rbenv,可以和 pyenv 一样在本地管理多个 ruby 版本,很久没有更新本地的 ruby 版本导致了 jekyll 的依赖不支持才想起来这件事情。

安装

其项目地址为:

https://github.com/rbenv/rbenv

因此安装就很方便

git clone https://github.com/rbenv/rbenv.git ~/.rbenv

然后将下面内容添加到 PATH

export PATH="$HOME/.rbenv/bin:$PATH"

运行

~/.rbenv/bin/rbenv init

根据依赖将输出内容,添加到 ~/.zshrc

重启shell,或者 source ~/.zshrc 使设置生效

再运行检查脚本

curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash

一切没问题就OK。

rbenv install 命令不在 rbenv 中,而是在 ruby-build中,可以通过下面的命令安装

apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6 libreadline6-dev zlib1g zlib1g-dev
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

如果是 Debian(>=7) 或者 Ubuntu (>=12.10) 也可以使用

sudo apt-get update
sudo apt-get install rbenv ruby-build

使用

rbenv install --list       # 查看可用
rbenv install 2.5.0        # 安装版本

rbenv 中的 Ruby 版本有三个不同的作用域:全局(global),本地(local),当前终端(shell),和 pyenv 类似。

查找版本的优先级是 当前终端 > 本地 > 全局。

rbenv global 2.1.2
rbenv local 2.1.2
rbenv shell 2.1.2

reference


2018-03-04 linux , ruby , versions

每天学习一个命令:du 找出哪个文件夹占用空间

最近 VPS 磁盘空间一直上涨报警,就想查看一下哪个文件夹占用空间比较大,可以腾出一些可用空间来。查了一圈发现 du 命令就是该功能。du 全称 disk usage,

du 文档中就是这么描述他的功能的 —- 文件占用的空间,具体用法

du [OPTIONS] ... [FILE] ...

和绝大多数的命令一样,支持很多的选项,最常用的和 df 命令一样 -h,可以记忆 --human-readable ,用比较人性化的单位,比如 K,M,G。

所以这样就可以使用

du -d 2 -h <dir> | grep '[0-9\,]\+G'
sudo du -h --max-depth=1

来快速的找到占用空间比较大的文件夹,这里的 -d 实际是 --max-depth 的缩写形式,也就是查看 dir 目录下,最多往下查找 2 层,然后以 -h 比较友好的方式输出结果。

用法

除了上面提到了 -h 参数,du 命令还有一些其他的参数

当我们使用 -h 选项时命令会根据不同的大小给出合适的 K, M, G 单位,方便查看,但如果想要强制命令输出统一的单位可以使用 -BM

这里将 -BM 拆开,-B 表示的是 --block-size=SIZE, M 表示的是兆,同理可以使用 -BG 强制使用 G 单位。

查看当前目录及其指定深度目录的大小

du -ah –-max-depth=0
  • -a 显示目录中所有文件及文件夹大小
  • -–max-depth=n 这个选项也能简写成 -d n: 深入到第 n 层目录,此处设置为 0,即表示不深入到子目录,设置为 1,则超过 1 层深度则忽略

忽略目录或文件

du --exclude=/path

只报告目录占用空间总量

-s 显示总和

du -hs /path

如果使用 du -h 那么会打印出 path 下所有目录的占用情况,如果使用 -s 那么只会输出 /path 占用的空间。

额外报告总量

使用 -c 选项会额外在最后打印两行总占用量

du -ch /Download

例如:

..
..
3.3G	Downloads
3.3G	total

分割子目录占用

通常情况下 du 会打印目录及其下所有子目录大小,加入有一个目录 Parent,下方有 SubDirA,SubDirB,还有很多的文件在 Parent 目录下,那么想要知道所有在 Parent 下文件占用,但是不想包括 SubDirA 和 SubDirB 的空间,那么可以使用 -S 选项。

du -h -S -d 2 /path/to/Parent

外延

熟悉了 du 命令之后,还有一个可视化更好的工具叫做 ncdu,在终端中使用比较友好的展示来显示磁盘空间占用。

更多的命令使用方法可以参考 tecmint


2018-03-04 linux , du , df , disk-space , disk

kodi 盒子上的媒体中心?

经常听说 Kodi,却一直没有时间了解一下,最近整理盒子 应用,突然间想起了这个被很多人称为的神器。

什么是 Kodi

Kodi 是一个强大媒体播放软件,支持 Macos, Windows, Linux, iOs 以及 Android 等众多平台,能在各种手机、电脑、平板以及机顶盒中运行。并且因为 Kodi 强大的媒体播放能力,被很多人成为家庭影院必不可少的应用。Kodi 拥有上千种插件,大大扩展了它的功能,丰富的 Kodi 插件为 Kodi 提供了无数的可能。Kodi 的插件种类很多,有音视频源插件,有字幕插件,有影视内容索引插件,有链接搜索助手插件等等。

下载并安装 Kodi

从官网上下载 kodi 写下文章时最新的版本为 17.6,选安卓 64 位

Kodi:https://kodi.tv/

备份地址:

  • http://mirrors.kodi.tv/releases/android/arm64-v8a/kodi-17.6-Krypton-arm64-v8a.apk
  • https://mirror.de.leaseweb.net/xbmc/releases/android/arm64-v8a/kodi-17.6-Krypton-arm64-v8a.apk

比如要在斐讯盒子 T1 中安装 Kodi,首先去盒子的设置 - 高级 - 远程调试打开,如果可能就把盒子的 IP 设置为固定 IP,这个 IP 下面命令中需要使用到。

通过 adb 安装过程如下:

adb connect <ip>
adb shell
adb install /path/to/kodi.apk

设置 Kodi

中文设置

  1. 初次进入 Kodi,选择左侧最上方三个按钮中的第二个图标“system”
  2. 选择“Interface settings”,点击左侧最下方的“Basic”菜单,点 3 次切换到“Expert”模式
  3. 选择“Skin”,更改“Fonts” 为 “Arial based”
  4. 点击左侧 “Regional” 菜单
  5. 更改“Character set” 为 “Chinese Simplified(GBK)”,更改“Language”为“Chinese Simple”
  6. 上述步骤严格按照顺序操作

添加文件安装源

  1. 点击“系统”-“系统设置”,点击左侧最下方的“基础”菜单,点 3 次切换到“专家”模式
  2. 点左侧的“插件”菜单,把“未知来源”项打开
  3. 返回到系统菜单,进入“文件管理”(file manager)
  4. 点击“添加源”,比如输入路径:http://srp.nu, 为源取个名字,更多的源地址,可以看下文
  5. 回 KODI 主页,点击“插件”,点左侧最上方第一个图标“插件浏览器”
  6. 选“从 zip 文件安装”,选择之前设定的名字,安装 zip 文件
  7. 安装完成后,返回上一级,选“从库安装”
  8. 选中需要安装的插件,安装

kodi repo 源

如何安装源这里有两篇详细的图文教程可以参考:

  • https://www.vpnranks.com/kodi-repositories/
  • https://www.vpnranks.com/superrepo-kodi-repository/
  • https://github.com/taxigps/xbmc-addons-chinese/
  • http://archive.org/download/repository.xvbmc
  • https://kodiapps.com/builds-chart
  • https://fusion.tvaddons.co/
  • http://lvtvv.com/repo/
  • http://kodi.emby.media

在安装插件源的时候可能会遇到这几个名词

  • 14.x Helix
  • 15.x Isengard
  • 16.x Jarvis
  • 17.x Krypton

其实这是 Kodi 的版本代号。

总结

其实看到这里就能看到 Kodi 其实绝大部分的功能都是可代替的,流媒体播放固然强大,但是我更喜欢将资源通过 samba 共享出来,在盒子上使用小白播放器,或者在手机上使用 ES Explorer 访问;Kodi 中的直播流功能强烈的依赖于整理好的直播流,而盒子上的超级直播,HDP 直播等等 应用都能很好的代替直播流;再其次 Kodi 带的 DLNA,AirPlay 投屏功能,其实装一个乐播投屏就能完美解决,更不用说我之前的两台海美迪自身就携带 DLNA,局域网投屏本身问题也不大;最后再是 Kodi 的强大的插件库,虽然强大,却无奈经年无人维护,虽然有无数的插件可以使用,却只有寥寥几个可用。所以最后其实 Kodi 也不是居家必备的良药,对于折腾我始终抱有这样的态度,用起来比怎么用要重要的很多,真正用起来才是一个软件应该提供的,我在盒子上话费时间最多的其实就是播放本地局域网共享的视频,其实本身这个功能并不需要那么强大的 Kodi,当然 Kodi 也可以,至于强大的媒体库,对于我这样看完就删,真的只有经典的才保存的玩家来说,太奢侈。


2018-03-03 android , tv , kodi , media

使用Python控制Headless Chrome

首先要解释一下 Headless Chrome,通俗的讲就是运行一个没有GUI的Chrome,在 Headless Chrome 出现以前有 PhantomJS ,但是自从 Headless Chrome 出现之后 PhantomJS 活跃度下降,所以维护者就宣布 了停止继续开发。那么 Headless Chrome 能够什么呢?自动化测试,网页截图,网络调试,爬虫等等任务。Google 说在可预见的未来会一直维护

关于 Headless Chrome 官方有两篇教程

在 Headless Chrome 之前使用 Python 可以结合Chrome推出的 chromedriver 来操作 PhantomJS,那么现在有了Chrome的Headless模式怎么来控制Chrome就是这篇文章要讲的内容。

Chrome DevTools Protocol

在此之前几个重要的网址:

Google官方维护了一份协议叫做 Chrome DevTools Protocol,只要是实现了这一份协议就能够编程来控制Chrome,Chrome 自带的开发者工具其实也是这一份协议的实现

再看几个 Chrome Devtools Protocol 中的概念:

  • Browser 实例可以拥有多个 Page
  • Page 拥有至少一个 frame: main frame, 其他的 frame 可能被网页标记 iframe 和 frame 创建
  • Frame 拥有一个可执行的上下文,在该上下文中 JavaScript 可以被执行,Frame 中也可能有浏览器扩展 extensions 产生的内容被执行

可以用这张 来显示其结构。

常用API

  • Browser 浏览器版本,关闭,命令行等等管理操作
  • Page 该域包含和页面相关接口,页面加载,资源内容,截图,打印等
  • Network 网络请求,Cookie,缓存,证书等内容
  • DOM 文档DOM的获取,修改,删除等
  • Runtime 该域下暴露 JavaScript 相关运行时接口,可以用来执行代码

本地启动 Headless Chrome

本地启动 Headless Chrome 可以参考这篇文章

如果需要使用 Docker 来启动Headless Chrome 也可以使用

docker run -it --rm --name alpine-chrome -p 9222:9222 einverne/alpine-chrome

更加具体的使用介绍可以查看 GitHub

启动之后可以访问: http://localhost:9222/json 来查看是否启动成功。

pychrome

pychrome 是 Chrome Devtools Protocol 的 Python 实现,其他语言的实现,可以查看这个项目。Chrome官方推荐js/nodejs的实现 chrome-remote-interface 还有 node.js 实现的更高层级的 Puppeteer

这里主要摘录几个常用的操作

截图

使用 Page.captureScreenshot

def screenshot(browser, url, filename='image.png'):
    tab = browser.new_tab()
    tab.start()
    tab.call_method('Page.navigate', url=url, _timeout=5)
    tab.wait(10)
    # 截取当前Tab屏幕,结果为图片内容Base64
    screen_base64 = tab.call_method("Page.captureScreenshot")
    image_data = screen_base64.get('data', '')
    with open(filename, 'wb') as f:
        f.write(image_data.decode('base64'))
    tab.stop()
    browser.close_tab(tab) 

打印PDF

同样使用 Page 下方法

def print_to_pdf(browser, url, filename='file.pdf'):
    tab = browser.new_tab()
    tab.start()
    tab.call_method('Page.navigate', url=url, _timeout=5)
    tab.wait(10)
    pdf_data = tab.call_method('Page.printToPDF', landscape=False).get('data')
    with open(filename, 'wb') as f:
        f.write(pdf_data.decode('base64'))
    tab.stop()
    browser.close_tab(tab)

向下翻页

def perform_input(browser):
    """向下浏览页面"""
    tab = browser.new_tab()
    tab.start()
    tab.Page.enable()
    tab.Page.navigate(url='https://www.douban.com/', _timeout=5)
    tab.wait(5)
    # 更多 keycode 可以参考 https://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx
    keycode = int(0x22)
    tab.Input.dispatchKeyEvent(type='keyDown', windowsVirtualKeyCode=keycode, nativeVirtualKeyCode=keycode)
    tab.wait(3)
    screen_base64 = tab.call_method("Page.captureScreenshot")
    image_data = screen_base64.get('data', '')
    with open("keyDown.png", 'wb') as f:
        f.write(image_data.decode('base64'))
    tab.stop()
    browser.close_tab(tab)

获取网页HTML

获取动态网页的网页内容,等待JS执行完成后获取HTML

def get_html(browser, url):
    tab = browser.new_tab()
    tab.start()
    tab.call_method('Page.navigate', url=url, _timeout=5)
    tab.wait(10)
    html = tab.Runtime.evaluate(expression="document.documentElement.outerHTML")
    tab.stop()
    browser.close_tab(tab)
    return html['result']['value']

操纵网页元素注入JS

下面这段代码是访问 baidu,输入关键字,并点击搜索按钮,解析搜索结果并打印

def perform_click(browser):
    tab = browser.new_tab()

    # def loading_finished(**kwargs):
    #     print "[loading finished]"
    #
    # # when HTTP request has finished loading
    # tab.set_listener("Network.loadingFinished", loading_finished)

    tab.start()

    # call method
    # tab.Network.enable()
    tab.Network.enable()
    tab.Page.enable()
    tab.Runtime.enable()

    def dom_content_event_fired(**kwargs):
        print "[content] dom content event fired"
        tab.DOM.enable()
        root = tab.DOM.getDocument()
        root_node_id = root.get('root', {}).get('nodeId', '')
        # 找到输入框
        input_box = tab.DOM.querySelector(nodeId=root_node_id, selector='#kw')
        # tab.DOM.setNodeValue(nodeId=input_box, value='hello')
        tab.Runtime.evaluate(expression='document.getElementById("kw").value="Chrome"', )
        # 找到搜索按钮
        search_btn = tab.DOM.querySelector(nodeId=root_node_id, selector='#su')
        remote_node = tab.DOM.resolveNode(nodeId=search_btn.get('nodeId', ''))
        # 执行点击
        tab.Runtime.callFunctionOn(functionDeclaration='(function() { this.click(); })',
                                   objectId=remote_node.get('object', {}).get('objectId', {}))
        tab.wait(3)
        # 输出结果
        html = tab.Runtime.evaluate(expression="document.documentElement.outerHTML")
        html_value = html.get('result', {}).get('value', '').encode('utf-8')
        soup = BeautifulSoup(html_value, 'html.parser')
        l = soup.select('h3 > a')
        for result in l:
            print result.text
            print result['href']

        screen_base64 = tab.call_method("Page.captureScreenshot")
        image_data = screen_base64.get('data', '')
        with open("test.png", 'wb') as f:
            f.write(image_data.decode('base64'))

        # tab.DOM.performSearch(query='xpath', includeUserAgentShadowDOM=True)
        # stop the tab (stop handle events and stop recv message from chrome)
        tab.stop()

        # close tab
        browser.close_tab(tab)

    tab.set_listener("Page.domContentEventFired", dom_content_event_fired)

    # tab.call_method("Page.reload", ignoreCache=False)
    tab.call_method("Page.navigate", url='https://www.baidu.com', _timeout=5)
    tab.wait(20)

完整的代码可以参考 GitHub

其他可学习的网站

这篇文章讲述了使用 nodejs 的库 NickJS来爬取网站的要点。

这篇使用 nodejs 的chrome-remote-interface,来抓取网页。

其他

  • https://stackoverflow.com/questions/28430479/using-google-chrome-remote-debugging-protocol
  • https://blog.phantombuster.com/web-scraping-in-2017-headless-chrome-tips-tricks-4d6521d695e8
  • https://stackoverflow.com/questions/7848878/how-to-use-google-chrome-remote-debugging-protocol-in-http
  • https://github.com/auchenberg/devtools-remote
  • https://github.com/auchenberg/chrome-devtools-app
  • https://intoli.com/blog/running-selenium-with-headless-chrome
  • https://duo.com/blog/driving-headless-chrome-with-python

2018-03-01 chrome , headless-chrome , linux , python

Linux 下的 Android emulators

待办事项中一直有一个 Genymotion 模拟器的处理,挂在待办已经好几个月了,终于有时间来找一找 Linux 的安卓模拟器了, Genymotion 曾经很好用,可惜的是如今似乎已经收费。

Official

当然第一想到的就是 Android 开发者官网上提供的官方模拟器,虽然早先被诟病不少,但是似乎更新迭代很快速,现在几乎没有什么特别大的问题。

Anbox

这是我 Google 出来的第二个结果,他官网的标语就是可以再 GNU/Linux 系统上运行任何 Android 应用程序。根据官网的介绍, Anbox 和 Genymotion 的虚拟化不一样, Genymotion 是在操作系统上完整的虚拟化整个系统,而 Anbox 直接使用宿主机的硬件和内核来运行 Android 程序。目前 Anbox 没有可视化界面可以安装 Apk,可以使用命令 adb install path/to/app.apk 来安装。

Anbox 这个项目还是属于起步阶段,但是体验还是非常不错的,如果遇到安装之后无法打开,或者无法安装 Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113] 这种错误时,也不沮丧。

如果要在 Anbox 中安装 arm 和 Google Play 可以参考这个项目

官网地址:https://anbox.io/

Genymotion

很可惜的是他已经不再提供免费的开发者 License。

官网:https://www.genymotion.com/

reference


2018-02-28 android , linux , emulator

Grafana 基本使用

Grafana 是一个开源的时序性统计和监控平台,或许用这么简单的一句话无法表现 Grafana 的强大。下面是官方列出的 6 大功能,但其实细分起来 Grafana 要强大更多。

  • 可视化
  • 报警
  • 支持很多数据源,InfluxDB,Elasticsearch,MySQL 等等
  • 全平台支持
  • 无数的 dashboardsplugins
  • 支持用户系统和协作

更多 Feature 见 官网

安装

非常简单,官网就很详细

默认的账户密码都是 admin

基本概念

Data Source

数据源:Grafana 获取数据的配置,支持以下数据源

  • Graphite
  • InfluxDB
  • OpenTSDB
  • Prometheus
  • Elasticsearch
  • CloudWatch

从 4.3 版本开始支持 MySQL。

每个数据源都有一个独立的查询编辑器,用来动态从数据源获取数据,并展示到 Panel 上。

Organization

组织:支持多组织,以支持各种部署模式,包括使用单个 Grafana 实例为多个组织提供服务。

用户、数据源和仪表板都隶属于组织。

用户隶属于某个组织后。就拥有该组织下的所有数据源和仪表板。

User

用户: Grafana 的帐户。用户可以属于一个或多个组织,并可以通过角色分配不同级别的权限。

Role

在给每个新用户分配组织时,可以指定其角色。角色有:Admin、Editor 、Read Only Editor、Viewer。默认为 Viewer。

Dashboard

仪表板:由一行或多行的面板组成。仪表板可以看做为一个展示单元(栏目),该单元由一行或多行组件构成,每行又可以由一个面板或多个面板组成。

仪表板的时间段可以由仪表板右上方的仪表板时间选择器控制。

Row

行: 仪表板内的逻辑分隔符,用于将面板组合在一起。一行里可以有一列或多列面板。

Panel

面板:Grafana 的可视化构建块,所有的数据展示都是在面板上实现的。

每个面板都有各种各样的造型和格式化选项,让你创建完美的图片。

目前有四种面板类型:Graph,Singlestat,Dashlist,Table 和 Text。

  • Graph 面板允许你根据需要绘制出许多指标和系列。
  • Singlestat 面板需要将单个查询减少到单个数字。
  • Dashlist 和 Text 是不连接到任何数据源的特殊面板。

可以通过插件安装的方式来扩展面板类型。例如:Pie Chart、Worldmap Panel。

面板上的时间范围通常是仪表板时间选择器中设置的时间范围,但可以通过使用面板特定时间覆盖来覆盖。

Query Editor

查询编辑器:用来显示数据源,并根据数据源查询其包含的指标。

将鼠标放在面板的 Panel Title 位置,然后单击,就会显示出查询编辑,点击 Edit,就显示出查询编辑器了。

Grafana 允许您在查询编辑器中按照它们所在的行来引用查询。如果您向图形添加第二个查询,则可以通过键入#A 来引用第一个查询。这提供了一种简单而方便的方法来构建复合查询。

Templating

模板允许更多的交互式和动态的仪表板。可以让你轻松的批量生成同一类型的查询,而不用一个个添加这些 Panel。

可以根据需要自定义变量参数作为查询查询条件,这些变量参数可以是固定的,也可以是通过应用服务提供的数据,还可以是数据源动态查询的数据。

配置

如果是使用的 deb 安装,配置文件路径

/etc/grafana/grafana.ini

[database]

此处的数据源与前面提到的数据源不同,此处的数据源用来存储 Grafana 的用户、仪表板等 Grafana 自身的信息。

默认用 SQLite3 数据源,一般也不用修改,也可以修改为 MySQL。

[security]

默认的 Grafana 管理员用户名为 admin,密码为 admin,可以进行修改,管理员密码也可以在页面中修改。

admin_user = admin
admin_password = admin

[users]

用户设置

# 是否允许新用户注册,默认为 true,如果不想让人随意注册,可以关闭
allow_sign_up = false

# 是否允许用户自己创建组织,默认为 true,为了便于管理,组织统一由管理员创建,不允许普通用户创建
allow_org_create = false

# 是否将新用户自动归属到主要的组织上(组织 id=1)。当设置为 false 时,将自动为该新用户创建一个新的组织。
auto_assign_org = true

# 新用户默认的角色
auto_assign_org_role = Viewer

其他更多见 官网

Dashboard 及语句

在 Grafana 中使用 SQL 语句,这部分待补充

Plugins

Grafana 支持非常多的插件,可以扩展数据源,或者扩展显示,或者用来增强一些功能。


2018-02-27 grafana , go , monitor

搭建自己的文件共享服务 linx server

之前用过 https://sm.ms 这个非常好用的图片共享站,界面非常简洁,延迟也低,就想着是不是自己也能够搭建一套这样的服务私用,然而 sm.ms 并没有开源,连其 Android/iOS 客户端也并没有开源,所以只能在网上寻觅代替品,幸而遇到了 linx server

同样是一个文件分享的站点,通过 Docker 搭建一套服务非常简单,他也能够支持使用 API 上传,界面也同样非常简洁。具体的使用可以参考 Docker 页面

docker pull einverne/linx-server
docker run -p 8080:8080 -d -v /media/meta:/data/meta -v /media/files:/data/files einverne/linx-server

源码

源码中使用的框架和工具:

  • flag 标准库中的命令行参数
  • Goji ,一个简单的 Web 框架。
  • pongo2 Django 语法类似的模板引擎
  • bencode bencode 编码解码库

2018-02-26 linux , server , file , media , sharing , photo , linx-server

Workflow for iOS 使用指南

Workflow 是 iOS 上一款可以实现自动化过程的应用,在 iOS 的框架内是先自定义的流程,比如发送最后拍摄的一张照片到 Instagram 这样的操作。他被 Apple 买下之后就免费开放给所有人使用了。有效的使用 Workflow 能够简化在手机上重复的操作。

Workflow 的功能应该由使用者决定,而不是开发者,所以 Workflow 和编程语言一样,需要学习。

Workflow

下面先介绍一些 Workflow 能够做到的事情,然后从中去学习 Workflow 制作的过程,从而能够自己完成自动化流程。

图片九宫格

将方形图片切割为 9 格图片,Workflow 地址

Google 粘贴板

用 Google 搜索当前粘贴板中的文字或者图片,Workflow

隐身相机

在不启动相机界面的同时拍照,并保存到相册, Workflow 地址 这一个 Workflow 只有一个选项选择前置还是后置摄像头,如果你想要更加复杂的 Workflow 允许你选择连拍数量的可以使用这个

下载到小米路由器

在手机上复制下载链接运行该 Workflow 即可,地址

切分全景图

将横向的全景图切分为多个图片方便分享到 Instagram,地址

每天领取支付宝红包

支付宝去年推出的分享领红包活动,虽然一开始诚意满满,不过后来就只能每天领 1 毛了,不过 1 毛也是肉嘛,反正 Workflow 点一下够省事,地址

网易云音乐听歌识曲

一键打开网易云音乐听歌识曲,地址

网购历史价格查询

下载文件

下载文件到本地或者 Dropbox

下载 Instagram 图片和视频

下载 YouTube 视频

网购历史价格查询

获取 bilibili 视频封面

还有更多好用的可以从下面的网站上获取,我平时常用的

  • App Store 换区
  • Instagram 下载
  • Google 以图搜图

更多的 Workflow 可以从下面网址获取

还有一个实用技巧就是实用 Google 的 site 搜索语法,比如想要搜索 Instagram 相关的 Workflow,则可以在 Google 中输入 Instagram site:https://workflow.is/workflows/

如果你常用 RSS,那么可以在 InoReader 中订阅该组合包:http://www.inoreader.com/bundle/0014cd63bb38

自定义

通过上面的一些例子应该可以看到一些端倪,其实 Workflow 就是把一些常用的操作给编程化,比如最简单的支付宝领取红包,其实就是使用 Safari 打开一个链接。如果再复杂一些比如切割图片,涉及到一些宽高计算,可能还有些 IF 的判断。如果再复杂一些比如 Instagram 图片下载,涉及到了下载网页内容用正则去匹配关心的内容,在比如 Google 以图搜图,涉及到了 Post 请求,然后拼凑网页链接再打开。

最最重要的一点就是网络服务提供足够的 API 能够让 Workflow 能够轻易的调用,如果有翻译服务提供了公开可调用的 API,我们就可以在 Workflow 中,获取粘贴板内容,将内容发送给翻译服务请求结果,并且将结果以通知或者其他形式告诉给用户,这样一个翻译的 Workflow 就实现了。

reference


2018-02-25 workflow , ifttt , automatic , ios

Squid http 代理

Squid 是一个Web代理软件,可以轻松的实现 HTTP,HTTPS,FTP 代理,通过缓存常用请求,Squid 能够减少带宽使用,提高响应速度。

sudo apt-get update
sudo apt-get install squid

Squid 的默认配置文件存放在 /etc/squid/squid.conf

sudo vim /etc/squid/squid.conf

Squid 的默认端口是 3128,配置文件中可以 http_port 3128 来设置

Squid 默认是不允许任何客户端连接的,通过修改配置允许所有客户端连接

http_access allow all

修改完成后重启代理服务

sudo service squid restart

reference


2018-02-24 linux , ubuntu , squid , proxy , webproxy , http , https

dockerfile 指令

通常情况下,我们并不使用 docker commit 方法来构建镜像,而是使用 Dockerfile 的定义文件和 docker build 命令来构建镜像。更多 Docker 入门 的内容可以参考之前的文章。

每条指令都会创建一个新的镜像层并对镜像进行提交,Docker 大致上按照下面的流程执行 Dockerfile 中的指令:

  • Docker 从基础镜像运行一个容器
  • 执行指令,对镜像做出修改
  • 执行类似 docker commit 的操作,提交一个新的镜像层
  • Docker 再基于刚刚提交的镜像运行一个新容器
  • 执行 Dockerfile 中下一个指令,直到所有指令执行完毕

常见的命令 RUNEXPOSE 之外,Dockerfile 还支持其他很多指令。

CMD

CMD 指令用于指定容器启动时要运行的命令,类似 RUN,但是 RUN 指令是指镜像被构建时要运行的命令,而 CMD 是指定容器被启动时要运行的命令。运行的命令放在一个数组结构中

docker run 命令可以覆盖 CMD 指令

如果 Dockerfile 有多个 CMD 指令,只有最后一个会生效。

CMD 指令有很多种格式,最常见,也是官方推荐的格式是:

CMD ["executable", "param1", "param2", ...]

ENTRYPOINT

ENTRYPOINT 指令和 CMD 指令非常类似,之前说过 CMD 指令会被 docker run 命令覆盖,而 ENTRYPOINT 指令提供的命令不容易在启动容器时被覆盖。实际上, docker run 命令行中的指定的任何参数都会被当做参数再次传递给 ENTRYPOINT 指令中指定的命令。

ENTRYPOINT 可以让容器以应用程序或者服务的形式运行。

ENTRYPOINT 也有很多使用方式,比较推荐的是:

ENTRYPOINT ["executable", "param1", "param2" ]

WORKDIR

WORKDIR 指令用来在从镜像创建一个新的容器时,在容器内部设置一个工作目录,ENTRYPOINT 或 CMD 指定的程序会在该目录下执行。

可以通过 -w 参数在运行时覆盖工作目录

sudo docker run -it -w /var/log ubuntu pwd

ENV

ENV 指令用来在镜像构建过程中设置环境变量,新的环境变量能在后续任何 RUN 指令中使用。

ENV RVM_PATH /home/rvm

同样也可以使用 -e 参数赖在运行时添加环境变量。

USER

USER 指令用来指定镜像会以什么用户去运行

USER nginx

镜像会以 nginx 用户去运行,同样也可以使用 -u 选项来覆盖该指令

VOLUME

VOLUME 指令用来像基于镜像创建的容器添加卷,一个卷可以存在一个或者多个容器内的特定目录,这个目录可以绕过联合文件系统,提供共享数据或者对数据持久化功能

  • 卷可以在容器间共享和重用
  • 对卷的修改是立即生效的
  • 对卷的修改不会对更新镜像产生影响
  • 卷会一直存在直到没有任何容器使用

卷功能让我们可以将数据,比如源代码,数据库等其他持久化内容添加到镜像中,而不是预先将这些内容提交到镜像内部,卷允许我们在多个容器间共享内容,可以利用此功能测试容器和内部应用代码,管理日志,处理内部数据库等等。

VOLUME ["/opt/project"]

该指令会基于此镜像创建的任何容器创建一个名为 /opt/project 的挂载点。

ADD

ADD 指令用来将构建环境下的文件和目录复制到镜像中。

ADD 指令通过目的地址参数末尾的字符来判断文件源是目录还是文件,如果目标地址以 / 结尾,那么 Docker 就认为源地址指向的是一个目录,如果目的地址不是 / 结尾,那么源地址就是文件。

COPY

COPY 指令和 ADD 很类似,根本不同是 COPY 只关心在构建上下文中复制本地文件,而不会去做文件提取和解压的工作。

如果目的位置不存在, Docker 会自动创建所需要的目录结构

ONBUILD

ONBUILD 指令能为镜像添加触发器,当一个镜像被用作其他镜像的基础镜像时,该镜像中的触发器会被执行。触发器会在构建过程中插入新指令,我们认为这些指令是紧跟 FROM 之后执行的。触发器可以是任何构建指令。

reference

  • 《第一本 Docker 书》

2018-02-23 linux , docker , docker-image

电子书

本站提供服务

最近文章

  • AI Shell 让 AI 在命令行下提供 Shell 命令 AI Shell 是一款在命令行下的 AI 自动补全工具,当你想要实现一个功能,敲一大段命令又记不住的时候,使用自然语言让 AI 给你生成一个可执行的命令,然后确认之后执行。
  • 最棒的 Navidrome 音乐客户端 Sonixd(Feishin) Sonixd 是一款跨平台的音乐播放器,可以使用 [[Subsonic API]],兼容 Jellyfin,[[Navidrome]],Airsonic,Airsonic-Advanced,Gonic,Astiga 等等服务端。 Sonixd 是一款跨平台的音乐播放器,可以使用 [[Subsonic API]],兼容 Jellyfin,[[Navidrome]],Airsonic,Airsonic-Advanced,Gonic,Astiga 等等服务端。
  • 中心化加密货币交易所 Gate 注册以及认证 Gate.io 是一个中心化的加密货币交易所。Gate 中文通常被称为「芝麻开门」,Gate 创立于 2013 年,前身是比特儿,是一家致力于安全、稳定的数字货币交易所,支持超过 1600 种数字货币的交易,提供超过 2700 个交易对。
  • 不重启的情况下重新加载 rTorrent 配置文件 因为我在 Screen 下使用 rTorrent,最近经常调试修改 rtorrent.rc 配置文件,所以想要找一个方法可以在不重启 rTorrent 的情况重新加载配置文件,网上调查了一下之后发现原来挺简单的。
  • Go 语言编写的网络穿透工具 chisel chisel 是一个在 HTTP 协议上的 TCP/UDP 隧道,使用 Go 语言编写,10.9 K 星星。