Ubuntu 开机启动图形界面应用程序

概述

目标:开机全屏运行浏览器,自动打开指定网址;

环境:Ubuntu 18.04

分析

整理一下大致思路,比较简单:

1. 取消桌面启动,减少资源浪费;
2. 用户自动登陆;
3. 自动打开图形界面应用程序;

准备

更换apt-get源

系统启动后,第一件事就是把apt-get的源修改为国内镜像,本文用的是阿里源,配置过程如下:

cd /etc/apt/
# 习惯性操作
$ sudo cp sources.list sources.list-bak
# 将下面一段代码替换掉sources.list原来内容
$ sudo vi sources.list
# ------------------start---------------------
deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
# ------------------end---------------------

# 更新源地址
$ sudo apt-get update

软件包安装

chromium-browser是必须的,其他软件包根据自己的需求。

$ sudo apt-get install vim
$ sudo apt-get install nginx
$ sudo apt-get install chromium-browser

开始

设置系统运行级别

系统启动默认进入字符界面的配置有2种方式:

1. 修改grubquiet splash改为text

2. 使用systemd来设置runlevels
本文主要是第二种方式,Ubuntu使用systemd而不是init,因此runlevels的概念被术语target所取代。因此init-based runlevelssystemd-based targets之间确实存在关系,映射如下:
┌─────────┬───────────────────┐
│Runlevel │ Target │
├─────────┼───────────────────┤
│0 │ poweroff.target │
├─────────┼───────────────────┤
│1 │ rescue.target │
├─────────┼───────────────────┤
│2, 3, 4 │ multi-user.target │
├─────────┼───────────────────┤
│5 │ graphical.target │
├─────────┼───────────────────┤
│6 │ reboot.target │
└─────────┴───────────────────┘
如果只是修改当前runlevels,执行 sudo systemctl isolate multi-user.target即可
咱们要修改默认runlevels,执行以下命令:

$ sudo systemctl enable multi-user.target
$ sudo systemctl set-default multi-user.target
# 设置后查看runlevels,结果为:N 3
$ runlevels

重启后系统自动进入字符界面,如果想启动桌面,执行startx即可

设置用户自动登陆

$ sudo mkdir  /etc/systemd/system/getty@tty1.service.d/
$ sudo vim /etc/systemd/system/getty@tty1.service.d/override.conf
# 将以下内容写入文件保存
# ------------------start---------------------
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noissue --autologin sql %I $TERM
Type=idle
# ------------------end---------------------

设置浏览器自启动

编写启动脚本

启动浏览器需要有X11的支持,借鉴startx的思路:先启动xserver,再启动client;其实把client部分换掉就行了。

$ cd /usr/bin/
$ sudo cp startx mystartx
$ sudo vim mystartx

mystartx中找到这段内容:

xinit "$client" $clientargs -- "$server" $display $serverargs

在它前面插入:

client=/usr/bin/chromium-browser
clientargs=" --start-maximized --start-fullscreen --disable-session-crashed-bubble http://www.u396.com"

设置自启动

打开~/.bashrc文件,在最后追加一下内容:

cc=`ps axuw|grep chromium-browser|wc -l`
xc=`ps axuw|grep xserver|wc -l`
echo "chromium-browser process:${cc}, x11 server process:${xc}"
if [ $cc -lt 2 ] && [ $xc -lt 2 ]; then
       	/usr/bin/mystartx	
fi

结束语

折腾了几个小时,重启服务器,面子上算是搞定,其中的问题欢迎大家指正。一直以来主要用centos,最后一次使用ubuntu大概十年前了,记得当时免费申请光盘,要了一箱,送给同学,然而没送出去几套,不禁有些感慨。当年在学校时,在大牛民工于某的影响下,几个发行版都玩了玩,其中印象比较深还有Magic,中文支持比较好,现在不知道怎么样了。

sqlplus Linux版本安装和使用

以下介绍SQLPLUS的Linux版本安装及使用,其他版本下载及文档见Oracle Instant Client Downloads

下载

我的服务器为x86-64,要找对应系统版本,打开Instant Client for Linux x86-64进入下载页面,优先考虑当前最新版本为12.2.0.1.0,选择接受许可协议“Accept License Agreement”,下载以下三个包:

  1. 必要的基础程序 instantclient-basic-linux.x64-12.2.0.1.0.zip
  2. 一些库和sqlplus可执行文件 instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
  3. 包含应用开发需要的头文件以及Makefile示例 instantclient-sdk-linux.x64-12.2.0.1.0.zip

需要登录方可下载

安装

解压压缩包

解压后会自动创建并将文件解压至instantclient_12_2文件夹,将instantclient_12_2移至/usr/local并对动态库做软连接

mv instantclient_12_2 /usr/local/
cd /usr/local/instantclient_12_2
ln -s libclntsh.so.12.1 libclntsh.so
ln -s libocci.so.12.1 libocci.so

安装 libaio

sudo yum install libaio

设置环境变量

echo 'export LD_LIBRARY_PATH=/usr/local/instantclient_12_2:$LD_LIBRARY_PATH' >> ~/.bash_profile
echo 'export PATH=/usr/local/instantclient_12_2:$PATH' >> ~/.bash_profile
source ~/.bash_profile

优化命令行使用

其实到此已经可以使用了,为了用起来更方便,我们需要安装rlwraprlwrap是一个wrapper,它接收我们输入的命令并交给我们指定的程序去执行,同时使用GNU readline库提供命令行编辑功能并且记录命令历史,将会使你的命令行用起来更加方便(主要是sqlplus太难用了)。

yum install -y rlwrap
echo 'alias sqlplus="rlwrap sqlplus"' >> ~/.bashrc
source ~/.bashrc

OK,现在可以放心去用了。

连接使用数据库

  • 连接本机数据库 sqlplus username/password
  • 连接远程数据库 sqlplus username/password@//domain:port/dbname

Gulp插件制作 – 使用流处理

强烈建议写插件的时候支持流处理,本文是关于创建插件支持流的介绍。确保遵循规范处理错误,在内容处理的同时进行异常捕获。

使用流处理

我们来实现一个文件文本处理的插件,这个插件支持`file.contents`所有可能的形式。

var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

// consts
const PLUGIN_NAME = 'gulp-prefixer';

function prefixStream(prefixText) {
  var stream = through();
  stream.write(prefixText);
  return stream;
}

// plugin level function (dealing with files)
function gulpPrefixer(prefixText) {
  if (!prefixText) {
    throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
  }

  prefixText = new Buffer(prefixText); // allocate ahead of time

  // creating a stream through which each file will pass
  var stream = through.obj(function(file, enc, cb) {
    if (file.isBuffer()) {
      this.emit('error', new PluginError(PLUGIN_NAME, 'Buffers not supported!'));
      return cb();
    }

    if (file.isStream()) {
      // define the streamer that will transform the content
      var streamer = prefixStream(prefixText);
      // catch errors from the streamer and emit a gulp plugin error
      streamer.on('error', this.emit.bind(this, 'error'));
      // start the transformation
      file.contents = file.contents.pipe(streamer);
    }

    // make sure the file goes through the next gulp plugin
    this.push(file);
    // tell the stream engine that we are done with this file
    cb();
  });

  // returning the file stream
  return stream;
};

// exporting the plugin main function
module.exports = gulpPrefixer;

上面的插件可以这样使用

var gulp = require('gulp');
var gulpPrefixer = require('gulp-prefixer');

gulp.src('files/**/*.js', { buffer: false })
  .pipe(gulpPrefixer('prepended string'))
  .pipe(gulp.dest('modified-files'));

一些使用流的插件

Gulp插件制作 – 使用缓冲区

本文是一些创建插件操控缓冲区的信息内容。

使用缓冲区

如果你的插件是依赖于基于库的缓冲区,你将可能会选择基于插件的file.contents作为缓冲使用,让我们实现一个在文本文件的内容增加前缀的插件:

var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

// consts
const PLUGIN_NAME = 'gulp-prefixer';

// plugin level function (dealing with files)
function gulpPrefixer(prefixText) {
  if (!prefixText) {
    throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
  }

  prefixText = new Buffer(prefixText); // allocate ahead of time

  // creating a stream through which each file will pass
  var stream = through.obj(function(file, enc, cb) {
    if (file.isStream()) {
      this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!'));
      return cb();
    }

    if (file.isBuffer()) {
      file.contents = Buffer.concat([prefixText, file.contents]);
    }

    // make sure the file goes through the next gulp plugin
    this.push(file);

    // tell the stream engine that we are done with this file
    cb();
  });

  // returning the file stream
  return stream;
};

// exporting the plugin main function
module.exports = gulpPrefixer;

继续阅读

Gulp插件制作指南

我们强烈建议每个开发者遵循本指导规范,没有人喜欢使用差的插件,这些规范会帮助你制作出更加完美的插件。

指南规范

  1. 您的插件不应该做非常容易实现的功能
    • 比如:删除文件目录不需要插件,在任务里面使用del功能就可以了;
    • 不要为了包装而包装,这样可能会降低插件质量;
    • Gulp插件是基于文件的操作,如果你发现自己强制在一个流中处理复杂的操作,请替换为正常的node模块来代替;
    • 一个好的插件实例应该像`gulp-cooffee`一样,`coffee-script` 和`Vinyl`脱离box将无法工作,所以我们将此功能抽象打包为插件使之正常工作;
  2. 您的插件应该只做一件事,并且将之做好
    • 避免配置选项让插件做不同的工作;
    • 例如:一个JS压缩插件不应该有添加header的选项;
  3. 不要重复其他插件的工作
    • 不要实现concat功能,因为已有了gulp-concat插件;
    • 不要实现添加headers功能,因为已有了gulp-header插件;
    • 不要实现添加footers功能,因为已有了gulp-footer插件;
    • 如果它是常见且可选的用例,注明你得插件一般同其他插件使用;
    • 尽量使用现有插件,这将减少你得代码量并且确保生态系统的稳定;
  4. 你得插件必须经过测试
    • 测试gulp插件非常容易,你甚至都不需要gulp去测试它;
    • 多看一下其他插件的例子;
  5. 在`package.json`中添加`gulpplugin`作为关键词,这样搜索的时候才会展示你的插件;
  6. 不要在流里面抛出错误
    • 替而换之,你应该发出一个错误时间;
    • 如果你在流的外面遇到了错误,例如你在创建流的时候发现无效的配置,可以跑出错误;
  7. 以你的插件名字作为错误信息的开头
    • 例如:gulp-replace: Cannot do regexp replace on a stream;
    • 使用`gulp-util`的 PluginError 对象使之更加简单;
  8. `file.contents`类型的文件,自始至终保持一致
    • 如果文件为null或者无法读取,请忽略并继续;
    • 如果文件作为流输入,并且你的插件不支持,请抛出错误;不要缓冲一个流强制塞进插件中与其他流一起工作,这将可能引起严重的问题。
  9. 在做完操作之前,不要进入下一个管道处理。
  10. 克隆一个文件或者基于文件创建新文件的时候,请使用 file.clone() .
  11. 使用推荐模块页面上面的模块将会使你的工作更加简单。
  12. 不要作为依赖来引用 gulp
    • 使用 gulp 测试或者自动化你的插件工作流程非常酷,需要确保将之放在devDependency里
    • 作为依赖引用gulp,意味着安装你的插件还需要安装gulp和它的所有依赖;
    • 一般来说,插件没有任何必要需要依赖gulp,如果你的代码中确实这么做了,请告诉我们来帮助你。

继续阅读

JQuery:除指定区域外点击任何地方隐藏DIV

没事玩玩 Google nav 中个人通知功能的效果,点击通知后展现浮层,点击其他区域任何地方隐藏浮层,样式上的东西都好说,展现和隐藏是如何做到的呢?还是google一下,找到stackoverflow的大婶们给的解决方案。

$('body').click(function(e) {
    var target = $(e.target);
    // 如果#overlay或者#btn下面还有子元素,可使用
    // !target.is('#btn *') && !target.is('#overlay *')
    if(!target.is('#btn') && !target.is('#overlay')) {
       if ( $('#overlay').is(':visible') ) $('#overlay').hide();
    }
});

或者

$('body').click(function(e) {
   if(e.target.id != 'btn' && e.target.id != 'overlay')
      if ( $('#overlay').is(':visible') ) $('#overlay').hide();
})

AngularJs斗争经验总结(二)

闲来无事,斗争一下 select 标签,其中 ngOptions 是关键指令,可指定数据源,需要注意的是使用 ngOptions  指令的同时需要指定 ngModel , ngModel 用来绑定数据,比如:ng-model=”contry” ,在选中对应的county后,选定的值会绑定到 $scope.country 上面。 继续阅读

AngularJs斗争经验总结(一)

AngularJs 非常强大,它彻底摆脱了传统的前端开发方式,无缝的进行数据绑定,使用它做前端开发着实方便快速。最近开始使用它做项目开发,过程中吃了不少瘪,特此记录一下。

使用自身特性

开始使用AngularJs开发时,还是难免摆脱传统的思维方式,有些地方仍然使用Jquery动态修改数据和绑定事件(会被耻笑啊),其实AngularJs提供的特性已经能够满足我们大部分的需求。拿 inputselect 标签举例说明:

  1. input 不要使用 value 属性,尽可能使用 ng-model 指令。数据变化时,不会存在 value 和 defaultValue 不一致的问题。
  2. 尽可能使用 ng-keyupng-blurng-click 等指令进行事件处理。避免使用Jquery进行DOM绑定。
  3. select 要使用 ng-modelng-options 指令,这将大大减少模板的复杂度。

继续阅读

作为程序员最应该阅读的21本书籍

Stack Overflow上有网友提问,每个程序员应该阅读的最具影响力的书籍有哪些?他说:“如果能够回到以前,作为一个开发者,告诉自己在开始自己的职业生涯时应该阅读那些书籍,我希望这个列表内容丰富,涵盖范围广泛”。问题得到广大网友的积极响应,整个过程得到了213个回复,最终投票得出了94本有价值的书籍。我们摘取前21本书推荐给大家。 继续阅读