Acuario
Acuario's Blog
2023-09-27T18:25:43+00:00
https://acuario.xyz/
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)
Hugo
《虽然人人都说暴力不好》读书笔记
https://acuario.xyz/others/everyone-says-that-he-that-violence-should-not-be-but-clip/
2023-09-27T18:25:39+00:00
2023-07-14T00:49:21+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p><img src="https://s2.loli.net/2023/07/14/ibvecJnfFZgNE4m.jpg" alt="读书笔记"></p>
<p>第9页<br>
人人都说暴力不好,为什么又会为它着迷?为什么又要崇尚暴力呢?真是奇怪。这其中一定有原因。
那便是:我们活着,本身就是一种暴力。</p>
<hr>
<p>第12页<br>
最原始的权力,就是以暴力为前提,令对方服从。暴力便是这样,不由分说地令对方服从,从而产生权力。当然,前提是要比对方强大,遭遇对方抵抗时,也具备将其压制到底的实力。只要能做到这些,就能以暴力获得权力。权力也是暴力的成果之一。
可以这样说,无论是食物、安全,还是权力,只要还有什么东西是不用暴力就得不到的,暴力就不会从我们的世界消失。于是,现实情况变成:暴力与我们形影相随、若即若离。所以,我们活着就是一种暴力。</p>……
<p><img src="https://s2.loli.net/2023/07/14/ibvecJnfFZgNE4m.jpg" alt="读书笔记"></p>
<p>第9页<br>
人人都说暴力不好,为什么又会为它着迷?为什么又要崇尚暴力呢?真是奇怪。这其中一定有原因。
那便是:我们活着,本身就是一种暴力。</p>
<hr>
<p>第12页<br>
最原始的权力,就是以暴力为前提,令对方服从。暴力便是这样,不由分说地令对方服从,从而产生权力。当然,前提是要比对方强大,遭遇对方抵抗时,也具备将其压制到底的实力。只要能做到这些,就能以暴力获得权力。权力也是暴力的成果之一。
可以这样说,无论是食物、安全,还是权力,只要还有什么东西是不用暴力就得不到的,暴力就不会从我们的世界消失。于是,现实情况变成:暴力与我们形影相随、若即若离。所以,我们活着就是一种暴力。</p>
<hr>
<p>第17页<br>
如果仅因为犯下凶案这一条理由,就同意将人处死,那就变成谁都可以用任何手段杀死凶犯。受害人的家属也可以抓住犯人,对他行刑。还有,既然依托于法律的死刑是被允许的,那么是否只要依托于法律,政府就可以将任何人处以死刑呢?答案必然是否定的。因此可以看出,只有“正当的理由”和“正当的程序”二者同时存在时,死刑才会为人们接受。
尽管如此,依然无法改变执行死刑就是杀人的本质。肯定死刑的人,在理由和程序上将死刑和普通的杀人区分开来,实质上也只是将杀人以好或不好来区分。因此杀人通常而言是不对的,却不意味着任何时候都绝不可以。只要理由和程序正当,在某种情况下杀人也无妨,即不否定所有的杀人行径。于是,在杀人这一终极暴力面前,我们依然要考虑它好坏与否。对于暴力,我们很难持彻底的中立态度。永远无法与暴力彻底划清界限,这或许就是人性的可悲之处。
可是这样一来,“杀人不对”这一道德标准就无法严密自洽。肯定死刑,就意味着认同在某种情况下杀人也无妨。当然,反对死刑,就意味着“绝不能杀人”这一道德标准占了上风。可是,既然多数人赞成死刑,“不能杀人”在社会中也就无法站稳脚跟——否则,大多数人就不会认为在某种情况下,杀人也无妨了。</p>
<hr>
<p>第22页<br>
“没人有权剥夺别人的未来”“每条生命都是无可取代的,没有谁能抹杀他人的存在”——这些也都是不能杀人的理由。但仔细思考,这些理由不过是换个说法把“不能杀人”重申一次。杀人就意味着“剥夺别人的未来”,也是“抹杀唯一的存在”。这些回答只是用其他说法表述“不能杀人”,并不能解释为何不能杀人。
“被杀死的人不能重生”的说法也是一样,“杀人”本就相当于“让对方不能重生”。</p>
<hr>
<p>第23页<br>
换言之,不能杀人不是根深蒂固的道德法则。乍看上去,这一准则似乎根本不需要理由,实际上,并不存在一个完备的理由证明它是完全正确的。既然如此,也就难怪许多人会认为在某些情况下杀人也没什么大不了。他们一定这样想:“原则上来说不能杀人,但既然没有一个确凿的理由,只要满足一定条件,就可以像执行死刑那样将人杀掉。”</p>
<hr>
<p>第24页<br>
话语无法赋予道德绝对的正义性</p>
<p>或许有人会因为找不到不能杀人的根本原因而不满,认为一定有某种绝对的理由能够支撑道德的正义,否则岂不是所有人都可以杀人了?
可是,找不到绝对理由支持的,不是只有“不能杀人”这一项道德要求。其实任何道理都一样,因为话语的性质就是如此。
到目前为止,话语仍无法赋予道德绝对的正义性。发生了A,形成了B;A和B以某种方式联系在一起一话语很适合用来记录或描述这些情形,却无法从根本上证明“为什么不能做A(或为什么应该做A)”。
就像我们试图从道德角度阐述“不能杀人是因为会有人伤心”时,立刻就会产生“为什么不能让人伤心(如果是为了让人伤心而杀人不就行了吗)”之类的反面论调。当我们继续对其反驳,则又会出现新的反对意见,如此循环不息。这就是所谓的无限递归。
因此,从话语的性质来看,不存在可以证明“不能杀人”这一道德正确性的理由。话语的性质只能说明“如果你杀了人,就会被捕,接受处罚”之类法律上规定的因果关系。</p>
<hr>
<p>第26页<br>
话语的无力</p>
<p>那么,话语是否对扶正道德毫无帮助呢?
也不能这么说。话语无法说明特定的道德根据,却可以说服人们接受某种道德。
用刚才的例子来说,“有人会伤心”无法从根本上说明“不能杀人”这一道德标准,却可以从“杀人后会有人伤心”这一因果关系上来描述事实。
“杀人会有人伤心”,只看这句描述,确实仅仅表达了“A导致B发生”这一因果关系。然而,同时也向对方传递了“因为杀了人会有人伤心,所以不能杀人”这一讯息。虽然只是记述事实,却有让听者接受某种行为规范的力量。这被称为话语的“述行性力量”。
也就是说,通过记述事物之间的关系,话语能够传递一定的道德信息,说服对方采取某种行为。正因为话语有这样的力量,才不能把它和道德分割开。尽管话语无法证明道德的绝对正确性,人们还是停止不了说教。就算无法清楚地说明为什么不能杀人,但从话语性质上来看,只要对方能接受“不能杀人是对的”就行了。</p>
<hr>
<p>第34页<br>
人们给道德寻找根据的行为,反而制约了道德。
当被问到为什么不能杀人时,我们便不由得中了圈套,很容易陷入必须找出一个理由作答的尴尬境地,担心若不这样做,“不能杀人”的道德原则会由此崩坏。可是,扶正道德的举动并不一定总能让它更加坚固,反而可能使其在特定条件或假说的限制下变得更加脆弱。看似维护道德的行为,实则是一种对道德的弱化。这便是道德的逆命题。
康德以定言命令式思考道德,是为了将道德从各类条件或制约中解放出来。定言命令式是无论何时何地都能无条件成立的道德律,换句话说,康德眼中真正的道德,是不需要任何理由做依据的。特定情况下无法成立的道德不是真正的道德——康德对定言命令式下的定义,就包含这一条。</p>
<hr>
<p>第50页<br>
因为谁都不能忽视,人是活在暴力当中的,无论你是否情愿。
前面强调过,这个世界上到处都是只能用暴力解决的事。生活中,我们也在不停判断某些特定的暴力是好的,还是坏的(或者至少是“无奈的”),甚至和康德一样,终日思考为了实现正义是否必须杀人,并非在任何情况下都深信不能行使暴力。当然,也有人认为“无论什么场合,暴力都是不好的”。可只要缜密地思考一番就会明白,这样的想法毫无意义。假想一位女性将要被人强奸,她身边恰好有一块大石头,于是用石头打了对方的头,逃出险境。
在这种情况下,我们能站在“一切暴力都不好”的立场上,反对她用石头打对方的行为吗?显然不能。如果反对,就相当于让她乖乖被侵犯,从本质上默认了加诸她身上的暴力。
也就是说,“任何情况下暴力都不好”这一看似恪守道德标准的观点和其表象相反,不过是眼看着暴力发生,却毫不反抗的“胆小鬼观点”,它反而肯定了暴力。这里我要再次重申,“任何情况下暴力都不好”看似在道义上很风光,从存在论的角度看却是完全错误的。即使在道德立场上否认我们活在暴力中的事实,也没有任何意义。如果不能直视这一点,就不可能批判真正的暴力(当然也不是让各位像康德那样赞成死刑。该赞成怎样的暴力、反对怎样的暴力,与眼下的问题无关)。只要我们还活在暴力中,就无法不用好坏来区分暴力的性质,对其做出价值判断。将暴力分为好的和坏的,会为我们分辨敌人和战友提供帮助。
政治世界就是这样诞生的。
卡尔·施密特在《政治的概念》中指出,敌人和战友的区别才是政治固有的指标。这里的“政治”指的是国家等政治概念,或权力行使、法律制定与战争等政治行为,也就是我们平时所说的“政治”或“行为主体”“行为”。这些政治主体组成世界的过程,从本质上来说就是区分敌人与战友的过程。施密特认为,区分敌人与战友的过程暗含着一种对立,最终可能引发两方相互残杀。他所说的敌人与战友,是以能否对对方行使暴力为基准来区分的。划分敌友的过程,产生了国家等政治主体。
不得不用好或坏来区分暴力,说明我们生活在一个必然的政治世界里。对我们来说,暴力究竟是什么呢?要理清这个问题,不能一直埋头于道德这片海洋中,还需要跨越到政治领域中去。</p>
<hr>
<p>第57页<br>
假设警察要抓一名罪犯。如果罪犯企图逃跑或反抗,警方就会使用暴力抓捕他。如果“暴力”这个词太重,也可以说以“物理实力”来抓捕他。总之要采取一种方式压制对方的攻击或抵抗,用更强的力量令对方屈从。如果罪犯的攻击或抵抗比警方的力量更大,警察就抓不住他了。所以警方必须做好准备,能够随时对罪犯行使比其攻击更强大的暴力。
同时,为了避免个人或其他组织拥有比警方更强大的力量,警察平时必须监视社会,取缔收缴暴力武器。正是这些与暴力息息相关的活动,才使国家拥有平息犯罪的力量。平息犯罪就意味着平息违反法律的行为,维护法律。换句话说,国家以暴力的方式,也就是所谓的“诉诸武力镇压”,来维护法律。
对一个国家来说,它需要妥善组织警方活动,预备好力量,以行使社会中最强大的物理实力。如果没有储备,一个国家就无法治理犯罪,进而无法维系法律,最终无法统治社会。所以说,国家是在暴力的基础上诞生的。</p>
<hr>
<p>第66页<br>
为什么国家能够成为“赋予暴力权利”的根源呢?因为只有国家才具备物理实力,能真正取缔社会中产生的暴力。社会上会出现各种各样的暴力,只有国家有实力取缔这些暴力,确定它们之中哪些是违法的,哪些又是合法的、属于正当防卫。而我们就算认为某种暴力违法,只要它还没被取缔,就会存在于社会,暴力行使主体就依然能够在国家掌控范围之外行使暴力。所以,唯有以暴制暴,才切实支撑着国家——支撑着“赋予暴力权利”的根源。</p>
<hr>
<p>第67页<br>
暴力合法与否由国家来区分;其实这不仅仅针对暴力,国家对任何行为都是如此,用“这样还可以,那样就不行”的论调来区分哪些合法,哪些不合法。由此确立人们能做哪些事,不能做哪些事。
判断其他行为是否合法,与确立“赋予暴力权利”的方式相同。国家用实力取缔它认定“违法”的行为,在社会上确立合法行为与违法行为的区别。用实力划分合法或违法这一本质始终不变。在我们看来,假若超越了国家认可的“合法行为”的界限,国家就会立刻发动被判定为合法的暴力,逮捕、处罚我们,实际上就是由国家活动划定人们行事的权利范围。我们能做什么、不能做什么,都是由国家法律规定的。不过,这里的“权利”可不仅限于人权之类的东西,它泛指一切被法律承认的行为的可能性。</p>
<hr>
<p>第68页<br>
国家是一场运动。它不断确立或判断哪些行为在法律界限内,哪些行为在法律界限外;同时以暴力(行使物理实力)取缔超越法律界限的行为,从而设定社会中的权利关系(得到法律承认的行为可能性之间的关系)。如此一来,我们就看清了国家的本质。国家的一部分重要职能,便是进行一场暴力运动。这项运动划定了人的权利——告诉我们什么能做,什么不能做。</p>
<blockquote>
<p>国家的定义——国家是一场持许存在的运动——垄断暴力,解释暴力,维护暴力垄断的运动。</p>
</blockquote>
<hr>
<p>第77页<br>
社会契约论的出发点认为人类原本是自私的,为了保护自身的安全或利益,什么事都做得出来。自然状态就是从这一观点出发推演而来的。
但社会契约论认为,人与人达成契约时抛弃了人的本性,对人类的“善意”怀抱期待。这是社会契约论的巨大矛盾,也是它的弱点。社会契约论的理论弱点</p>
<hr>
<p>第77页<br>
社会契约论还有一项致命弱点,它无法说明国家为什么临到近代才形成。
换言之,在历史的长河中,社会契约论一直无法说明在社会中扩散的暴力权利为何直到近代才被统合在一个机关下。
如果像社会契约论解释的那样,人们能够依照契约自发地形成国家,那人类社会诞生之后,国家怎么会一直都没出现呢?实际上,直到人类社会发展到近代,才第一次诞生了垄断暴力权利的国家。社会契约论的历史性弱点</p>
<hr>
<p>第85页<br>
近世身份制度不是与近代对立的古旧遗风,它为统治阶级独占暴力权利做了准备。也就是说,尽管丰臣秀吉的刀狩令在方方面面都不完备,但它是近代国家形成迈出的最有效一步。
刀狩令的目的根本不在于让百姓无法与统治权力对抗,而是一方面制约着人们原有的暴力权利,一方面试图将这一权利逐渐收于统治阶层的掌控之下。刀狩令并不完全限制百姓的拥刀权,但有效限制了使用暴力私了冲突的可能,并通过身份政治区分武士和百姓的暴力使用,收归暴力权利。</p>
<hr>
<p>第87页<br>
通过百姓自愿放弃的方式实现政府“合法独占暴力”,是根本不可能的。事实上,统一天下的秀吉也没有做到这一点——他是用军事力量强迫百姓放弃暴力权利。
简单地说,丰臣秀吉首先组织起足够打败其他大名和民众的绝对强势的武装力量,用它确立自己在一大片领地的统一支配权。这种压倒性的力量对比迫使人们交出手中的暴力权利,由丰臣秀吉的武装力量垄断支配。
前面讨论社会契约论的时候指出,让人们在自然状态下主动放弃暴力权利是不可能的。历史也证明确实如此。要让人们放弃一直拥有的暴力权利,需以绝对强势的武装力量为前提。社会契约论的历史性弱点,被历史事实证伪。暴力的收归,是由更强的暴力支撑的。</p>
<hr>
<p>第91页<br>
为何在丰臣秀吉的时代能够诞生一个让大部分地区的人都交出暴力权利的强大军事组织?
这个问题很难解答。其实,社会契约论无法解释这类历史问题。
德国社会学家诺贝特·埃利亚斯的论点很有启示意义。埃利亚斯指出,欧洲近代国家的形成与枪支火药的发达程度是分不开的(参照《文明的进程》《宫廷社会)。
这又是怎么一回事呢?
枪支火药的进步从根本意义上改变了军事形态。截至十六世纪,欧洲的战争都以军事贵族身披铠甲、骑马作战的重骑兵部队为战斗的主力军。这一军事形态要求每一位贵族战士具备很高的自主性。可以说,尽管是骑兵部队,贵族战士们跨上战马时的个人发挥仍是战斗成败的重要因素。那时的军事贵族拥有独立自主的能力,没有战事时可以自由回到领地,建立属于自己的权力空间。可以说他们归附于国王之下,但依靠自己的实力基础构建独立的权力空间团结作战。这便是当时国与国的战争方式。贵族战士之间如果发生矛盾,产生的武力纷争属于私战,是完全正当的。
可随着枪支火药的进步,军事贵族逐渐失去独立自主的能力。因为操控火药的步兵组成的集团战逐渐成为战争的主要方式。骑术精湛的骑兵在战场上一对一打败几个敌人的场面已经消失,他们在操纵火药的步兵部队面前几乎无力回天。这时,军事活动的主体从个人转移到了集团。
就这样,军事贵族愈发依赖或从属于统帅步兵部队的国王的权力。国王渐渐有了主动统帅兵力的能力,并开始限制以军事贵族为首的各阶层想方设法保有的暴力权利。
在考虑日本暴力垄断的形成时,欧洲国家的情况能带来很多启示。丰臣秀吉能够平定日本九州至东北的动乱一统天下,与他接手织田信长打下的军事基础密不可分。1543年,织田信长在军队中积极引入种子岛传来的火绳枪,从而大大改变了日本的军事状况。这一变化是颁布刀狩令的一大历史前提。秀吉通过刀狩令限制暴力权利,区分武士与百姓的身份,为近代国家垄断暴力打下基础。而使这一系列军事变化成为可能的,正是火绳枪的传人。枪炮火药的出现,降低了个人暴力要素的重要程度,这其实也是暴力收归的一种形式,暴力因为枪炮火药的出现,逐渐被收归到特定实体(即君主帝王)身上,成为垄断的暴力权利。</p>
<hr>
<p>第101页<br>
即使是受到恐惧威胁迫不得已定下的契约,只要在自然状态下成立,双方就必须遵从。其违法与否,是在有了国家之后依照国家内部的法律判定的。在国家从自然状态下诞生之前,它都不会是违法行为。
国家从自然状态下诞生的最原始契约必然是强制性契约。当然在国家出现之后,这类契约便会被判定为违法,由国家来消灭。可是,强制性契约恰恰对国家根基的稳固发挥着作用。这样的契约被国家认为是违法的,可同时又是国家存在的基础。说起来,这也算是一种矛盾。可只有这一矛盾能够判定各类暴力是否违法,因此也只得认为消灭暴力的暴力是合法的。这不过是矛盾的表现方式罢了。所以,纵然强制性契约是国家的基础,却不必感到悲伤,更不必贬低它。</p>
<hr>
<p>第118页<br>
国家之所以能够成为社会上暴力权利的唯一源泉,是因为国家握有能够制伏社会中其他任何暴力的物理力量,并宣称那些暴力是违法的。由暴力来制伏另一种暴力的运动,将暴力分成合法与违法两种。也就是说,只有当国家能发挥制伏其他暴力、并将暴力按照法律区分开来的强大力量时,它才能将自己的强制力归为合法一列。</p>
<blockquote>
<p>为什么只有国家才能强制征收民众的钱财呢?</p>
</blockquote>
<hr>
<p>第119页<br>
用暴力夺取人们的劳动成果,比主动付出体力劳动或做买卖挣钱方便得多。而且,这样做能让依靠暴力运动存在的组织专心于暴力运动或权力工作,让它们更加稳固。现如今的资本主义社会,如果没有钱,国家就无法运作任何活动。因此国家必须想方设法弄到钱。相比之下,国家付出体力劳动或做生意,一定没有动用暴力从人们手中收取钱财、再将自己举办的活动归属于暴力或权力范围内更有效率。想一想也不足为奇,黑社会就是欣赏这种高效,才用暴力使自己寄生于民众的经济活动之中。</p>
<blockquote>
<p>为什么国家要通过自认为合法的暴力向人们征收钱财?</p>
</blockquote>
<hr>
<p>第125页<br>
只有当战争目的是为了让对方承认某一事物属于自己的时候,才能将其称为“承认之战”。这场战斗同时也是让双方承认谁更强大、谁对谁拥有支配权的战斗。战胜的一方会迫使对方承认“我如此强大,所以要支配你,并有权征收你的劳动成果”。这也足够说明赌上性命的战斗是一场“承认之战”。可以说,这场战斗就是让对方承认自己的强大,承认自己对事物的主权、支配对方和征收对方劳动成果等一切的权利。换句话说,这场争战确立了社会上最基本的权利。</p>
<blockquote>
<p>黑格尔哲学中对暴力和权利的解释</p>
</blockquote>
<hr>
<p>第127页<br>
黑格尔论述的重点在于,所谓“权利”,不是直接成立的。只有当以暴力为背景的社会承认它时,它才算成立。权利与暴力的实践以及人们对暴力的承认是分不开的。</p>
<blockquote>
<p>这也是权利与义务同构的原因</p>
</blockquote>
<hr>
<p>第129页<br>
黑格尔用“赌上性命的战斗”理论将霍布斯“出于恐惧订立的契约”概念精细化了。也就是说,通过“有关承认的战斗”,确立了各种各样的权利。用社会契约论分析,这一进程指的就是原始契约使得国家从自然状态中应运而生。
社会契约论将这不断完善的进程称作“契约”,这本身就是一种法律学上的表现方式。黑格尔则将其称为“权利的承认”,从更深层面剖析何为法律。当有人企图从权利范围中逃脱时,以法律为名的暴力就会发动,打击超越法律范围的行为——这便是法律的特征。“以法律为名发动暴力”是区别道德等其他规范与法律的方式。而只有国家,才能确定人们可以行使怎样的权利,判断人们的行为是否脱离了法律的制约,并发动暴力打压脱离法律的行为。因此,国家不仅是社会上暴力权利的源泉,也是各种权利的源泉。换句话说,国家拥有确定并承认社会各类权利的权利。正是这围绕着权利的权利,造就了国家的本质。</p>
<hr>
<p>第136页<br>
若暴力已经使支配关系确立下来,又能够征取钱财,就只能用另一种暴力阻止它了。无论怎样游说对方暴力不好,只要对方动用了,我们还是无法抵抗。最终,只有另一种暴力才能制止暴力。也就是说,为了阻止国家成立,就必须有能够监视、取缔、抑制它的暴力机构。换言之,为了不让国家成立,就要建造另外的国家。</p>
<hr>
<p>第140页<br>
“应当消灭国家”这一想法出于对国家的批判:国家建立在暴力之上,以暴力为基础压榨民众,滥用权力。这些批评本身没有问题,甚至还是有必要的。但若是将这种批判思维转化为道德标准,认为国家是坏的,应当消灭,批判思维就变了味道,自己的道德标准就成了绝对的正确。如此一来,任何反对的呼声都成了道德上的“恶”,成为不惜一切也要打倒的东西。为了支持不容许建立国家的“道德善意”,人们可以做一切强制性的事情。最终,消灭国家的运动,将会孕育出更压制民众、更暴力的国家。</p>
<blockquote>
<p>消灭国家的道德论本身就是认可绝对暴力和建立国家的过程</p>
</blockquote>
<hr>
<p>第143页<br>
只要回到“国家是什么”的问题上,就能很好地理解一部分国家为何解体,一部分国家为何尚未形成。
国家是社会暴力权利的唯一源泉。也就是说,它是切实要求垄断社会合法暴力的组织。有了这一认识就不难明白,之所以有的国家解体,有的国家尚未成立,都是因为合法的暴力垄断尚未形成,也就是政府的力量薄弱;或者历史上的暴力垄断机制还没有发生作用,人们依自己的判断自由行使暴力。</p>
<hr>
<p>第146页<br>
国家确实以暴力让民众服从,有时甚至可能镇压民众。但没有国家,只是没有了合法的暴力垄断,暴力本身绝不会从社会中消失。
所以,无论有没有国家,我们都必须用某种方式应对暴力。</p>
<hr>
<p>第151页<br>
国家其实就是一种暴力体制,其内容就是通过社会上唯一合法行使暴力的组织以暴制暴。它不依据人们各自的判断随意发动,而是有原则地禁止人们行使暴力,依据社会中唯一受到法律承认的组织做出的法律判断制裁其他暴力。
因此,一般来说,国家还是遵循以暴制暴的公式;但它试图通过法律的调控予以制约——这就给人们提供了用不同于暴力的方法抵抗暴力的可能。所以说,国家的存在使人们能够用不同于“以暴制暴”的方式,制约压制其他暴力的暴力本身。法律的存在,让人拥有以暴制暴之外的抗暴方式</p>
<hr>
<p>以上摘自:<br>
<img src="https://s2.loli.net/2023/07/14/xa3T9Bmf1NtMbAO.png" alt="《虽然人人都说暴力不好》"><br>
<a href="https://book.douban.com/subject/30262316/">《虽然人人都说暴力不好》</a><br>
作者: [日]萱野稔人
出版社: 新星出版社
原作名: 暴力はいけないことだと誰もがいうけれど
译者: 烨伊
ISBN: 9787513325455</p>
播客札记(五):十大哉问
https://acuario.xyz/others/podcast-note-5/
2023-09-27T18:25:39+00:00
2023-04-05T19:23:10+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="十大哉问回答韩非压住我们千年的十个问题">十大哉问,回答韩非压住我们千年的十个问题</h2>
<p>本文系《翻转电台》十大哉问系列专题的收听笔记,播客节目链接如下:</p>
<ul>
<li><a href="https://pca.st/wsc5lmjl">引言:十大哉问,回答韩非压住我们千年的十个问题</a></li>
<li><a href="https://pca.st/g4ge1jrs">问题一:大多数人对道德声誉的追求都是假的,他们追求的是利益</a></li>
<li><a href="https://pca.st/xuookaax">问题二:人与人在不对称的权力和地位下,关系必然变糟</a></li>
<li><a href="https://pca.st/06wlqtc5">问题三:社会由中等人构成,道德教化作用有限,需要依靠惩罚</a></li>
<li><a href="https://pca.st/kahzart7">问题四:道德与情感实际上基于偏爱和立场,且非常嬗变,不及规则稳定</a></li>
<li><a href="https://pca.st/sp19jrjl">问题五:轻罪重罚,有利于遏制数量较多的罪行,阻止他们变得严重</a></li>
<li><a href="https://pca.st/fivmg3zu">问题六:惩罚对人才能起到根本的教育作用,道德太模糊,太弱</a></li>
<li><a href="https://pca.st/c6dtnylq">问题七:奖励的成本太高,对社会治理而言,惩罚的效益大得多</a></li>
<li><a href="https://pca.st/hgwy1gwi">问题八:个人利益最大化必然导致公共利益受损</a></li>
<li><a href="https://pca.st/5rq8gc23">问题九:一切都在发展,没有永恒的秩序,道德、制度、秩序必然发展变化</a></li>
<li><a href="https://pca.st/plihub4f">问题十:实利的关系,与功利主义?有什么区别?</a></li>
</ul>……
<h2 id="十大哉问回答韩非压住我们千年的十个问题">十大哉问,回答韩非压住我们千年的十个问题</h2>
<p>本文系《翻转电台》十大哉问系列专题的收听笔记,播客节目链接如下:</p>
<ul>
<li><a href="https://pca.st/wsc5lmjl">引言:十大哉问,回答韩非压住我们千年的十个问题</a></li>
<li><a href="https://pca.st/g4ge1jrs">问题一:大多数人对道德声誉的追求都是假的,他们追求的是利益</a></li>
<li><a href="https://pca.st/xuookaax">问题二:人与人在不对称的权力和地位下,关系必然变糟</a></li>
<li><a href="https://pca.st/06wlqtc5">问题三:社会由中等人构成,道德教化作用有限,需要依靠惩罚</a></li>
<li><a href="https://pca.st/kahzart7">问题四:道德与情感实际上基于偏爱和立场,且非常嬗变,不及规则稳定</a></li>
<li><a href="https://pca.st/sp19jrjl">问题五:轻罪重罚,有利于遏制数量较多的罪行,阻止他们变得严重</a></li>
<li><a href="https://pca.st/fivmg3zu">问题六:惩罚对人才能起到根本的教育作用,道德太模糊,太弱</a></li>
<li><a href="https://pca.st/c6dtnylq">问题七:奖励的成本太高,对社会治理而言,惩罚的效益大得多</a></li>
<li><a href="https://pca.st/hgwy1gwi">问题八:个人利益最大化必然导致公共利益受损</a></li>
<li><a href="https://pca.st/5rq8gc23">问题九:一切都在发展,没有永恒的秩序,道德、制度、秩序必然发展变化</a></li>
<li><a href="https://pca.st/plihub4f">问题十:实利的关系,与功利主义?有什么区别?</a></li>
</ul>
<h2 id="问题一大多数人对道德声誉的追求都是假的他们追求的是利益">问题一:大多数人对道德声誉的追求都是假的,他们追求的是利益</h2>
<p><img src="https://s2.loli.net/2023/04/05/JSiYKeZ9cNklAqC.jpg" alt="道德与纯洁性"></p>
<p>回答的假设是:一切道德与价值追求都是虚伪的,实际上大多数人能够追求的仅仅是利益。</p>
<ol>
<li>
<p>利益与道德追求的冲突矛盾几乎无处不在</p>
<ul>
<li>只要利益到位了,道德什么的都不重要</li>
<li>在具体事例的讨论中回应道德批判,为的是消解他人的主张,而无助于讨论本身</li>
</ul>
</li>
<li>
<p>为什么回应利益的动机如此简单?</p>
<ul>
<li>休漠认为力量最强的是对人的直接刺激,利益是奖励的刺激,痛苦是惩罚的刺激,所以人更容易接受利益剌激</li>
</ul>
</li>
<li>
<p>如何回应道德的动机?</p>
<ul>
<li>通常会用哲学打败哲学的方式,如黑格尔哲学的承认理论——承认的基石是价值 / 合法性,人类社会的本质是承认与寻求承认。但仅以承认理论又不足以立证道德与利益的冲突,因为道德与利益的冲突是非常自然的事,甚至超过承认理论。</li>
<li>通常也会使用互不冲突理论:二者并不冲突,其实是可以共存的,允许既要……又要……的情况发生。但相容理论的问题在于,为了把道德和利益进行对比,便将道德概念实在化,认为道德是如利益一样具有实利。而且,相容理论过于偏向于还原论,理据不够充分。</li>
<li>道理本质更像语言建制,是一个语言功能,而非实在物。</li>
</ul>
</li>
<li>
<p>道德与利益冲突的提问是巧妙的语言游戏。</p>
<ul>
<li>不应问:道德与利益冲突吗?</li>
<li>应该问:在什么情况下,道德与利益无关?</li>
</ul>
</li>
<li>
<p>道德概念的内涵</p>
<ul>
<li>道德通常与他人有关:
<ul>
<li>为别人承担危险,比如雇佣兵</li>
<li>成为领袖,引导大部分人</li>
<li>关心他人,医者仁心</li>
</ul>
</li>
<li>道德也可以与他人无关:追求自我卓越,成为他人的榜样</li>
</ul>
</li>
<li>
<p>纯洁性是否等于道德?</p>
<ul>
<li>综上(第 5 点),纯洁性只是道德的一个要素而非全部</li>
<li>纯洁性等于道德,是最容易走向<strong>道德虛无主义</strong>的路径。这个语言游戏将道德进行根本性的否定,是最粗暴的反对道德的方式。这也是今天最流行、最方便的反驳方式。</li>
<li>关键在于道德本身并不是公认的一无是处的东西,既然我们承认道德本身的作用,就不应对其进行根本性否定。而如果要对具体行为进行道德反驳,就要求讨论者从细节角度了解上下文和事情脉络,这样做的成本远比简单地否定道德要高,这也是为什么如今互联网上充斥道德虚无主义论调的原因。</li>
</ul>
</li>
<li>
<p>结论</p>
<ul>
<li>韩非说: 道德与利益相悖。这里的相悖只是关于道德语言建制的一个游戏规则,而非全部规则</li>
<li>我们不应陷入道德与利益的对比游戏,解决思路是找到语言游戏(非贬义)的多样性和丰富性</li>
<li>利益不是讨论问题的主因,而应从道德本身进行探讨</li>
</ul>
</li>
</ol>
<h2 id="问题二人与人在不对称的权力和地位下关系必然变糟">问题二:人与人在不对称的权力和地位下,关系必然变糟</h2>
<p><img src="https://s2.loli.net/2023/04/05/Ey7Zzw5gfiIPmlh.jpg" alt="不对称权力关系的解释理论"></p>
<p>回答的假设是:所有不对等,不平等的人际关系,一定是坏的关系,一定成为被惩罚支配的关系。</p>
<p>父母、父亲、师长、老板、领导,人际关系给予我们很大的压力,因此为了解释和解决这些压力。PUA、煤气灯效应、讨好型人格等等心理学概念被用以实现对这个问题的解释和解法,不过一个人际关系的问题,怎么会没有一个传统的视角呢?</p>
<p>韩非子认为不平等的关系一定是坏的关系,不平等的关系一定不可能有真实的情感和真实的尊重,而是充满了欺骗和危险的关系。</p>
<ol>
<li>
<p>权力关系的广泛</p>
<ul>
<li>上司和雇员,父母与子女的关系通常都存在权力关系的不对等。</li>
<li>在孔子对人际关系的想象中,一切关系都是父子关系。儒家以家庭伦理关系作为一切关系的基础。</li>
<li>法家认为一切关系都是君臣关系的模式,家庭关系也不例外。或者说不平等的关系一定是权力关系。</li>
</ul>
</li>
<li>
<p>单向义务论</p>
<ul>
<li>处在权力下位的人,对处在权力上位的人有单向的道德义务
<ul>
<li>在父母子女之中,单向道德义务以<strong>孝</strong>为核心</li>
<li>在夫妻关系之中,单向道德义务以<strong>贤</strong>为核心</li>
<li>在企业关系之中,单向道德义务以<strong>忠</strong>为核心</li>
</ul>
</li>
<li>单向道德义务在东方社会尤其明显,其已经形成了很多制度,建制和人际之间实际绑定的要求。如韩国职场的尊悲文化。</li>
<li>韩非认为,单向义务之所以成立的原因是,因为人是逐利的,即人是根本避免伤害的。当我们可以使用奖惩,尤其是使用惩罚来控制他人的时候,人就必然会这么做,或者说人就一定有这种使用惩罚的倾向。</li>
<li>在我们的文化传统当中,我们有一种自愿处于下位者的状态,很多人会自愿进入一个具有高度权力关系的组织。 如公务员系统。</li>
</ul>
</li>
<li>
<p>单向义务的二次攫取</p>
<ul>
<li>韩非式的礼教关系会获得一个虚伪的儒家:处于权力上位的人,不仅通过奖惩的方式去垄断、控制权力关系,在其中索要利益,其还在获取权力关系的合理性:
<ul>
<li>在父母子女之中,父母不仅要求子女对父母的孝顺,还对子女表现出慈的一面。</li>
<li>在夫妻关系之中,男方不仅要求女方贤惠,还表现出符合礼教规范的要求。</li>
<li>在企业关系之中,老板不仅要求员工对企业的忠诚,还要员工承认老板的义气。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>心理学解释的物理学倾向</p>
<ul>
<li>心理学对于关系的解决办法是不要讨好,学会拒绝</li>
<li>心理学尝试把问题做动机论的解释,认为找到动机就找到了一切的原动力,因此就可以解决问题,但实际上动机的解释在很大程度上是同义反复。</li>
</ul>
</li>
<li>
<p>PUA解释逻辑的拧吧</p>
<ul>
<li>心理学对机制的解释特别容易走向阴谋,煤气灯效应和 PUA 都有一定阴谋论的性质。但实际上问题本身不一定具有这种假定的阴谋,而有可能是单向义务的二次攫取,是对除了利益以外的合法性的攫取。</li>
</ul>
</li>
<li>
<p>祛除虚伪,还原利益反而增进权力关系</p>
<ul>
<li>解决不对等关系的问题,有一种比较粗暴的倾向,就是戳破情感的虚假,把关系还原为实际利益的关系。但这恰恰符合法家想要达到的关系治理目的——因为法家认为人之间的关系只有利益关系。</li>
<li>在父母夫妻企业劳工关系当中,由于历史和现实结构因素,必然存在「通过还原利益关系解决问题」途径的不可能。</li>
<li>真正平等的关系及其缺乏,可以说除了朋友关系之外,其他的关系在长期的情况之下,都会积累出很多不平等的要素。在这样的情况下,排除情感因素对处于关系当中的下位者是非常不利的。</li>
</ul>
</li>
<li>
<p>还原情感的情感属性</p>
<ul>
<li>孔子认为,拥有权利的人想要获得别人的忠诚,自己必须先以礼相待作为基础。如刘备诸葛亮之间先以礼相待,再回报以忠的关系
并不是所有的关系都是虚伪的,不能因为我们陷入过比较糟糕的法家式的权力关系,就此否定关系当中的情感要素,相反,情感恰恰是一个重要的解决路径。</li>
</ul>
</li>
<li>
<p>传统中有利于情感运作的部分</p>
<ul>
<li>在东方社会当中,「人情」的人际关系,有利于人与人之间的情感运作,「人缘」在组织中的影响力和说服力也更强。</li>
</ul>
</li>
<li>
<p>结论</p>
<ul>
<li>是否所有的不对等关系都会变得非常糟糕,变成奖励与惩罚的控制?某种程度上,我们或多或少都接受这个结论。尤其今天在心理学框架之下的情感,我们想把虚伪的情感从其中排除,回到纯粹利益。</li>
<li>由于接受了这个结论,我们发现自己遇到的很多不平等关系问题都难以处理,这也是为什么当今社会我们如此追求平等关系的原因。
接受某种程度上的不对等,学会在不对等的环境当中构造一个良好的秩序,是更重要的解决路径。</li>
</ul>
</li>
</ol>
<h2 id="问题三社会由中等人构成道德教化作用有限需要依靠惩罚">问题三:社会由中等人构成,道德教化作用有限,需要依靠惩罚</h2>
<p>回答的假设是:社会或一个组织由大量中等人构成,在这个环境下,以道德塑造秩序,要求大家都是很具有道德自觉的人,这虽然好,但很不现实。比较现实的条件下,我们不得不依靠奖惩形成秩序。</p>
<ol>
<li>
<p>中人社会及其丰富的外延观点</p>
<ul>
<li>法家的现实主义:儒家的道德虽好,但实现成本太高。儒家所要求的秩序是对道德水准较高的人秩序,但社会是由数量很庞大的道德中等人构成的,使用道德水准来构造社会秩序太过理想主义,很不现实。所以在韩非子看来,根本的秩序塑造,应该依靠奖励和惩罚。</li>
<li>在当下的环境,认可激励与道德的共存,实际上最后也必须认可韩非子的观点:对于绝大多数的人 我们只能使用奖励和惩罚,而非道德。</li>
<li>很多人都认可韩非的观点:构成中人社会绝大多数人的动机,只能依靠奖励和惩罚。要驱动一个人,就必须驱动其他的自利心,用利益驱动其行动;如果要阻止一个人,就需要屈服他的恐惧,即重刑主义。</li>
<li>中人社会的外延观点:
<ul>
<li>仓廪实而知礼节,道德是经济发展的产物:一个发展中国家的抄袭等行为是正常的。</li>
<li>Democracy 比较依靠较高人口素质,低人口素质实施就是灾难,例如英国脱欧</li>
<li>互联网乱象乃是因为网民人口中本科以上人数过低导致的</li>
</ul>
</li>
<li>结论:
<ul>
<li>如果没有激利,人很难呈现出利他的属性</li>
<li>如果没有惩罚 人很大惩都上 就会做出坏行为。eg. 互联网、呼唤重刑主义的场景</li>
<li>在没有惩罚,又有自利的条件下,人几乎一定会做出伤害的人的行为。eg. 马克思对于资本家的论断</li>
</ul>
</li>
</ul>
</li>
<li>
<p>无法为自己的长期利益和集体利益负责的“中人”</p>
<ul>
<li>中人特征:没有很好的道德,只能响应激利和刑罚,他们会因为短期的激利做出损害其长期激利的事,同时还可能做出损害整体利益的事。</li>
<li>根据中人的特征,在设计组织和社会秩序时,我们为了整体利益,可以限制中人的短激自利的行为。</li>
<li>中人的特质:
<ul>
<li>中人看中短激利,损害自己的长激利,因而损害整体利益</li>
<li>如果没有惩罚,又对自己有利,中人就会做出危害他的举动,中人做出坏行为的可能性和潜能很大。</li>
<li>因为中人太多,素质不够高,所以 Democracy 最后也会造成一种乱象</li>
<li>仓廪实而知礼节,不应对中人有道德期待,中人不太可能有道德秩序,不仅对其坏行为需要有一定宽容</li>
<li>对引导中人的行为趋向长期 / 共同利益,需要依靠惩罚去限制</li>
</ul>
</li>
</ul>
</li>
<li>
<p>韩非假设的基本前提——绝对权威</p>
<ul>
<li>反驳1️⃣:社会分工不一定具有道德价值,所以 KPI 的存在不一定是为了道德引导。无需取消 KPI 机制,不是因为人不道德、不能够负责。</li>
<li>反驳2️⃣:中人没有无条件的道德,而非没有道德。当今社会的道德退却,不是因为中人的道德问题,而是因为社会的高流动性。</li>
<li>反驳3️⃣:人的长期幸福与人的中短期受限,二者的价值无法客观衡量。长期幸福视角与短期施加的痛苦如何换算,是无法下结论的问题。</li>
</ul>
</li>
<li>
<p>中人社会话语——绝对权威的政治学</p>
<ul>
<li>当我们提出一个人生的长期利益,有什么确保其论断的绝对正确?在过去有宗教权威可以,但在韦伯所说的祛魅的世界中,不再存在这样的权威结论。</li>
<li>公共利益的权威性也如前所述,在神学的世界公共的利益是有权威性的,但当今社会的公共利益权威性不复存在。</li>
<li><strong>韩非子的中人社会视野成立的基本前提是权威价值的存在</strong>,中人必须绝对服从于高人,eg.君权神授、天子臣民、孔子的礼教</li>
<li>社会具有一种单项度:学历越高的人越容易接近权威的绝对真理,其对于广域问题的判断性更强,其视野更远、格局更大、道德水平更高,学历促使人抬到全面性更高的位置。</li>
<li>单一重高标准是绝对权威政治学的内容,但这种互联网想象本身难以成立。春秋战国时礼崩乐坏的作恶者,道德水平并不低。</li>
<li>暴力的恶在很多时候是与其所处环境息息相关,其中并不存在绝对权威的要素。暴力的恶的减少,并不用压抑其动机,在很大程度上是恶的土壤在慢慢消失,并非都是因为道德水平在提高。</li>
</ul>
</li>
<li>
<p>现代政治的命题:非道德、非幸福问题的</p>
<ul>
<li>绝对权威的政治想象是一个前现代政治,并不符合当今社会政治需要。</li>
<li>前现代政治为幸福政治负责,但现代政治不为幸福政治负责,这是相对主义的结果。</li>
</ul>
</li>
<li>
<p>韩非子中人社会视野占据主流,说明我们还未完成现代化</p>
<ul>
<li>韦伯定义的祛魅的世界指的是一个 祛除了为所有人的幸福负责的绝对崇高和绝对权威 的世俗的世界。世俗的世界最典型的特征就是相对主义,每个人都可以自己定义幸福。</li>
<li>霍布斯意识到了相对主义的存在,他认为我们需要一个权威来维持社会的底线秩序,这也是现代政治命题不管幸福,只管底线秩序的缘由。比较好的政体是让底线秩序得以维持,并确保其与底线的个人权力不矛盾,越好的政体处理二者的关系越好。</li>
<li>在祛魅的相对主义社会中,消极自由可以被容忍,因为幸福的重要程度低于伤害的重要程度,比起自我伤害,我们首先不能接受的是干涉他人自由。</li>
<li>亚当斯密认为:大多数情况下,商品社会中的秩序很多时候是不需要道德的,靠自律能够构成秩序。现代政治中的底线秩序不一定需要权威才能构成。</li>
<li>我们愿意接受韩非子的中人社会假设,是因为我们依然没有从现代性的视角审视道德问题,没能从相对主义的出发点思考解决办法,而依然相信绝对权威的存在。</li>
</ul>
</li>
<li>
<p>在现代社会中的道德和崇高</p>
<ul>
<li>现代社会中的道德和崇高,需要通过说服的方式和途径,而非权力的方式。</li>
<li>「这是我的个人看法」是一巧妙的避免纷争的说辞,这并没有避开论点与社会公共利益绑定的事实。这不助于良好的讨论与真理探索,也不是良好问题意识的表现。</li>
</ul>
</li>
</ol>
<h2 id="问题四道德与情感实际上基于偏爱和立场且非常嬗变不及规则稳定">问题四:道德与情感实际上基于偏爱和立场,且非常嬗变,不及规则稳定</h2>
<p>回答的假设是:道德本身有一个很大的问题,受到情绪和好恶的影响,因而非常嬗变。</p>
<p>韩非子举例《弥子瑕失宠》:</p>
<blockquote>
<p>昔者弥子瑕有宠于卫君。卫国之法,窃驾君车者罪刖。弥子瑕母病,人间往夜告弥子,弥子矫驾君车以出,君闻而贤之曰:“孝哉,为母之故,忘其犯刖罪。”异日,与君游于果园,食桃而甘,不尽,以其半啖君,君曰:“爱我哉,忘其口味以啖寡人。”及弥子色衰爱弛,得罪于君,君曰:“是固尝矫驾吾车,又尝啖我以余桃。”
故弥子之行未变于初也,而以前之所以见贤而后获罪者,爱憎之变也。</p>
</blockquote>
<ol>
<li>
<p>道德不存在?有可能是真的</p>
<ul>
<li>可以说,所有道德判断其实都是伪装的“好恶判断”。这是一种典型的道德虚无主义的提法,但万一这个提法是对的怎么办?</li>
<li>韩非子认为道德建基于情感的偏爱,所以它是很嬗变的,但规则本身是不变的,所以我们应该依赖规则,而不是道德。</li>
<li>马克思主义衍生出来的阶级道德论认为,道德具有阶级属性。资本主义道德维护的是资本主义的权利,比如很多人认为宽容、宽恕是用来压抑底层人反抗的,所以宽容、宽恕本身是不道德的。</li>
<li>道德演化论认为,道德是人们在演化的过程之中根据快感和痛苦慢慢演化而来的产物,其本质还是还是自立。</li>
</ul>
</li>
<li>
<p>所谓“道德非认知主义”</p>
<ul>
<li>韩非子或道德非认知主义形如「你这样的行为是不道德的」的论断,听起来是一个价值判断,但其实是伪装好的好恶判断。</li>
<li>简单来说,认为道德本身不存在,即是<strong>道德非认知主义</strong>。</li>
<li>认为道德是情绪判断、价值判断,进而否定道德本身的存在,这样的论断实际上是经过伪装的道德非认知主义。</li>
<li>维特根斯坦提醒我们要非常小心:很多时候我们做的道德判断和美学判断,不过就是好恶的同义反复而已,我们评价一个事物的道德,实际上就是在说它好。我们经常用这样的方式瓦解他人的道德感。eg. 恨国党遭遇的价值否定、清官难断家务事。</li>
</ul>
</li>
<li>
<p>道德判断都是伪装的“好恶判断”</p>
<ul>
<li>之所以我们容易接受「道德判断都是伪装的“好恶判断”」这一观点,是因为在很多情况下,我们认为毫无、关系的亲疏、喜欢不喜欢……比道德问题更切题,是一个对于现状更好的解释。这个现象在生活中比比皆是。</li>
</ul>
</li>
<li>
<p>我们能接受“道德的终结”吗</p>
<ul>
<li>反对道德非认知主义,将引导我们自己诉诸道德的权威性,这就要求绝对道德的存在。但世界上是否存在为真的道德命题?</li>
<li>道德定义存在一个同义反复的困境,如:「侮辱他人是不道德的」中,「侮辱」一词本身就具有贬义,延伸出来的论断本身并不具有物理事实那样的客观性。我们很难找到一个典型的道德事实对行为本身的道德性进行判断,道德判断本身的复杂性决定了其客观性的困难处境。</li>
<li>韩非子认为道德判断取决于视点(即不同视角),在不同立场和角度会有不同的道德判断</li>
<li>如今的道德并不存在康德所说的「命令式道德」,在某种程度上总有可以讨论道德判断的空间存在,而非有道德权威进行决定。</li>
</ul>
<blockquote>
<p>命令式道德是一种伦理哲学的观念,认为行为的正确性不取决于情境或后果,而是取决于行为规则本身,即行为本身是正确还是错误。在这一观念下,规则和命令是绝对的,行为者应该完全服从规则和指令,并且不应该考虑行为的后果和影响。
命令式道德的代表人物是德国哲学家康德,他提出了“绝对命令”(Categorical Imperative)的概念,认为行为应该基于一种普遍适用的道德原则,而不是基于具体的情境、目的或结果。
尽管命令式道德在某些情况下可能具有一定的意义,但它通常被认为是一种过分简化和概括的观念。在实际生活中,行为的正确性往往是基于情境和后果的,而不是基于简单的规则和指令。</p>
</blockquote>
<ul>
<li>如果我们彻底废除道德,我们就要把权力邀请进入道德的领域,让权力像韩非子所想的那样,订立法则来起作用。或者,我们必须找到非至尊道德运作的方式。</li>
<li>结论:道德不具有真理性——没有绝对的道德事实与道德命题契合。</li>
</ul>
</li>
<li>
<p>喜欢是个很个人的,很随意的吗?</p>
<ul>
<li>如今我们认为个人喜好是个人事务,而非公共事务,这是因为现代社会认可<strong>消极自由</strong>,而消极自由在很大程度上保护个人的喜好,支持其作为个人权利。</li>
<li>消极自由保护喜好的个人性和任意性,确保其不被非道德的力量禁止,而非别人的评价与限制。</li>
<li>个人的喜好很多时候并不是纯个人的事务,eg. 抽烟、特殊性癖……</li>
<li>个人喜好并非纯粹的个人事务,是因为其存在外部性——对别人有正外部性的就是好习惯,对别人有坏外部性的就是恶习。个人好恶只要存在外部性,就一定会被人评价。外部性的条件变化会导致我们的道德判断产生很大变化。</li>
<li>好恶与道德的差异,比我们想象的小得多。道德没有那么真理,喜欢没有那么个人。道德命题是伪装的好恶问题,但道德比好恶更多一些——价值判断——人有更多看问题的视角。</li>
</ul>
<blockquote>
<p>可欲之谓善,有诸己之谓信。充实之谓美,充实而有光辉之谓大,大而化之之谓圣,圣而不可知之之谓神。
——《孟子·尽心下》</p>
<p>释译:值得追求的叫作善,自己有善叫作信,善充满全身叫作美,充满并且能发出光辉叫作大,光大并且能使天下人感化叫作圣,圣又高深莫测叫作神。</p>
</blockquote>
</li>
<li>
<p>什么是“道德直觉”</p>
<ul>
<li>道德具有「视点」的特性,在不同视点可以得出不同的结论。人的思辨使人具有「视野」而非「视点」,能够从不同角度来看待问题。</li>
<li>康德命令式道德主张下,道德直觉是直接就能获得的、难以言喻的道德判断;</li>
<li>视角主义的道德主张下,道德直觉是指一个人根据自身经验,可以从相对正确的视角进行道德判断。一切不靠严格的推理和演绎,而是依据自身经验和感受获得的道德感觉。</li>
</ul>
</li>
</ol>
<h2 id="问题五轻罪重罚有利于遏制数量较多的罪行阻止他们变得严重">问题五:轻罪重罚,有利于遏制数量较多的罪行,阻止他们变得严重</h2>
<p>回答的假设是:对社会秩序的影响主要是由轻罪构成的,所以如果仅仅关注重罪,则错失了绝大多数真正的问题。且很多犯罪者从轻罪开始,慢慢走向重罪,遏制了轻罪,也就制止了这些人走向重罪。轻罪重罚还可以吓阻重罪。</p>
<p><img src="https://s2.loli.net/2023/05/11/6zyarbWGYO3xTQL.jpg" alt="问题五:轻罪重罚,有利于遏制数量较多的罪行,阻止他们变得严重"></p>
<h2 id="问题六惩罚对人才能起到根本的教育作用道德太模糊太弱">问题六:惩罚对人才能起到根本的教育作用,道德太模糊,太弱</h2>
<p>回答的假设是:统一的禁止性规范和惩罚,远远比纷繁的道理争论重要。</p>
<p>所以面对社会危机,我们是倾向儒家式的礼教过程?依赖哈贝马斯的“公共理性”,还是我们每次都大声疾呼“希望法律严惩!”</p>
<p><img src="https://s2.loli.net/2023/05/11/gqfVvPtCO9lHpbU.jpg" alt="问题六:惩罚对人才能起到根本的教育作用,道德太模糊,太弱"></p>
<h2 id="问题七奖励的成本太高对社会治理而言惩罚的效益大得多">问题七:奖励的成本太高,对社会治理而言,惩罚的效益大得多</h2>
<p>回答的假设是:惩罚是成本较低,实现可能性较高的社会秩序塑造方法,站在现实主义的角度,通过惩罚和纪律塑造社会秩序是最有效的。</p>
<p>这是一个有很大共识的社会信念,也是构成我们社会的基础组件——惩罚与纪律,这个方法到底有什么问题?</p>
<p><img src="https://s2.loli.net/2023/06/20/3YDrsoC8SaTjthE.jpg" alt="问题七:奖励的成本太高,对社会治理而言,惩罚的效益大得多"></p>
<h2 id="问题八个人利益最大化必然导致公共利益受损">问题八:个人利益最大化必然导致公共利益受损</h2>
<p>回答的假设是:公共利益与私人利益是大多数相悖的,过于强调私人利益,他们结成的公共共同体一定是软弱的。</p>
<p><img src="https://s2.loli.net/2023/06/20/vPZj2WfQknbR6Ma.jpg" alt="问题八:个人利益最大化必然导致公共利益受损"></p>
<h2 id="问题九一切都在发展没有永恒的秩序道德制度秩序必然发展变化">问题九:一切都在发展,没有永恒的秩序,道德、制度、秩序必然发展变化</h2>
<p>回答的假设是:社会道德、制度、文化都匹配一个具体的时期和状态,而人的社会是无限发展变化下去的,所以没有什么道德、制度和文化是永恒的,会不断发展出新的人类社会形式。永恒的人性与永恒的秩序都不存在,只有推陈出新的变化是永恒的。</p>
<ol>
<li>
<p>永恒秩序 vs 永恒流变,一个先秦就存在的争议</p>
<ul>
<li>是否存在永恒秩序?即 universal value,普世价值</li>
<li>孔孟的理论支持 universal value 的存在</li>
<li>孔孟价值更关注伦理,西方价值更关注自然权利,二者的共性是:权利的去中心化</li>
</ul>
</li>
<li>
<p>这个问题为什么重要?相对主义和历史主义</p>
<ul>
<li>永恒价值的重要性来源于问题的反面:如果没有永恒价值,世界会如何?</li>
<li>永恒价值的缺乏,会让社会走向相对主义和历史主义。</li>
<li>相对主义——不存在永恒秩序,不同情况下的价值不同</li>
<li>历史主义——来源于德意志特殊论,即没有适用于德国的永恒秩序。 => 最终走向战争</li>
<li>价值探索的意义在于确立坚实的信念。</li>
</ul>
</li>
<li>
<p>我们并非不相信自然秩序:反社会的自然需要</p>
<ul>
<li>人的本源追求——天性的解放和自我选择,这本身就是反社会的自然需要。</li>
<li>从人的角度出发,这种反社会的自然需要其实也是某种自然秩序——伊壁鸠鲁-卢梭式的自然秩序</li>
</ul>
</li>
<li>
<p>进入20世纪后这个问题讨论的困难:现代认识论</p>
<ul>
<li>
<p>基础人性的概念脱胎于宗教。人的基础人性在20世以后,失去了理论的支点。</p>
</li>
<li>
<p>现代认识论走向实用主义,需要高度形式化的意义上进行建构。</p>
</li>
<li>
<p>后现代的特征:确定性的瓦解。</p>
</li>
<li>
<p>「确定性的瓦解」成为秩序破坏者的武器,极大倾向秩序破坏者对确定性和秩序的破坏。一切秩序的丧失,让很多人将确定性构建于绝对权力和金钱。</p>
</li>
<li>
<p>自然权力退却后,个体通常有两个选择路径:</p>
</li>
<li>
<p>尼采:强力意志的自主立法,重构一切价值——上帝已死。</p>
</li>
<li>
<p>休谟:相信经验主义和自主演化秩序,走向相对保守的路径。</p>
</li>
<li>
<p>自然权力和自然秩序退却导致的结果:</p>
</li>
<li>
<p>自然权力的退场,同时也导致了对一切秩序的反对和质疑。</p>
</li>
<li>
<p>思维范式的进步,导致个体没能从尼采和休谟的路径中获得解脱,更没有让理论本身退却,而是导致了哲学病和理论的彻底大爆发。</p>
</li>
</ul>
</li>
<li>
<p>从最容易接受的自然秩序——平等,入手看待历史的两种理解</p>
<ul>
<li>平等是当今大多数人最能接受的一个自然秩序</li>
<li>从古至今的历史历程来看,平等 作为自然秩序越来越为人所接受</li>
<li>从历史从简到繁的角度来看,价值会随着社会发展不断繁复,但「平等」并没有遵循这一路径,而是越来越单一和完善。</li>
<li>从历史从繁到简的角度来看,历史是自然秩序不断完成的过程。这也是黑格尔的历史终结论的来源。自然秩序的完成,是人类社会活动不断促成的。</li>
<li>不是所有的东西都会「推陈出新」,平等观念的发展反映了韩非子「推翻旧物以新代之」观点的错误。</li>
</ul>
</li>
<li>
<p>为什么平等容易接受,从康德的论证入手</p>
<ul>
<li>
<p>种族主义、民粹主义、民族主义都是挑战平等观念的存在。eg. 纳粹、红色高棉</p>
</li>
<li>
<p>由于人对自身和他人相似性的总结——即人的自由意志的一致性,奠定了「平等」观念的根基。</p>
</li>
<li>
<p>康德所说的「自由」,指的是在人无法接近真理,无法接近物自体的基础上,受到先天和后天的影响而认识物自体,所以从中获得了自由。</p>
</li>
<li>
<p>理查德·罗蒂认为:生理性的科学和人的意识之间有一道无法逾越的鸿沟。</p>
</li>
<li>
<p>康德认为人的自由意志的根深蒂固,让平等观念深入人心。</p>
</li>
<li>
<p>自由的基础是基于现象学的——人所面对的都是现象,而不是对象。这也是现代认识论的基础。</p>
</li>
<li>
<p>语言是公用建制,语言现象学作为人类活动的重心,很大程度上决定了人的认识,也即决定了人的自由。</p>
</li>
<li>
<p>自由产生于人类认识的缺乏,人类只能认识语言现象学,而无法认识物自体对象本身(真理),这也就产生了不同角度和理解和认识——这就是自由本身。</p>
</li>
<li>
<p>人的认识与认识之间没有高低之分,这就是脱胎于自由而产生的平等。</p>
</li>
</ul>
</li>
<li>
<p>一个戏法:从人的不完美推出私有财产的必要</p>
<ul>
<li>儒家认为:人是不可能自足的,人对他人的依赖是必然的。也正因如此,儒家认为伦理秩序是自然秩序。</li>
<li>哈耶克的从人的非完备性,推论出私有产权的必要性:</li>
</ul>
<pre tabindex="0"><code> 没有人拥有完全的知识
=> 没有人能够做出完全的计划
=> 社会秩序不是从上至下的计划体系,而是一个不断扩展的秩序
=> 社会知识存在不同的重要程度
=> 形成社会秩序最重要的知识是价格
=> 如何让人能够遵循价格行事?
==> 私有产权的必要性
</code></pre><ul>
<li>哈耶克的推论说明,从人的非自足性、自由、平等是可以推论出自然秩序的。这个过程在弥合实用主义理论和自然权利理论,同时也在弥合康德和休谟。</li>
</ul>
</li>
<li>
<p>现象学、语言学、经济学,可能是新的自然秩序论证的基础。</p>
</li>
</ol>
<h2 id="问题十功利主义侵蚀了道德造成一个精致利己主义的社会吗">问题十:功利主义侵蚀了道德,造成一个精致利己主义的社会吗?</h2>
<p>回答的假设是:法家反对道德,功利主义同样反对道德话语,在这个意义上,他们相似吗?功利主义对道德的反对是否造成了同样的问题呢?</p>
<p><img src="https://s2.loli.net/2023/09/28/gPyjZiJU2hEGQ5A.jpg" alt="功利主义侵蚀了道德,造成一个精致利己主义的社会吗?"></p>
中银香港银行卡开户攻略
https://acuario.xyz/others/bochk-debit-card/
2023-09-27T18:25:39+00:00
2023-03-26T13:47:06+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p><img src="https://s2.loli.net/2023/03/26/rUNIe6a7YnwW2su.jpg" alt="中银香港奥海城分行"></p>
<p>疫情结束香港开放通关,可能因为刚开放的原因,近期内地人员赴港开户门槛很低(疫情前门槛普遍都比较高,有 20-100w 存款要求等),在🍠上看了不少攻略,本着可以不用,不能没有的精神,这个月准备好材料去开通了中国银行(香港)的储蓄卡。这里稍作记录,给需要的朋友做参考。至于为什么选中银香港,主要还是因为门槛低,用着也省心,没有其他心智负担。<br>
如果你问为什么需要开一张港卡,那说明你不是本文受众,可以不用往下看。</p>……
<p><img src="https://s2.loli.net/2023/03/26/rUNIe6a7YnwW2su.jpg" alt="中银香港奥海城分行"></p>
<p>疫情结束香港开放通关,可能因为刚开放的原因,近期内地人员赴港开户门槛很低(疫情前门槛普遍都比较高,有 20-100w 存款要求等),在🍠上看了不少攻略,本着可以不用,不能没有的精神,这个月准备好材料去开通了中国银行(香港)的储蓄卡。这里稍作记录,给需要的朋友做参考。至于为什么选中银香港,主要还是因为门槛低,用着也省心,没有其他心智负担。<br>
如果你问为什么需要开一张港卡,那说明你不是本文受众,可以不用往下看。</p>
<hr>
<h2 id="准备材料">准备材料</h2>
<ul>
<li>🪪身份证</li>
<li>🪪港澳通行证</li>
<li>📃白色通关凭条(入境HK时获取)</li>
<li>💰建议 1w HKD 现金备用,提前在内地银行 App 购汇,然后银行网点取现</li>
<li>📄地址证明:
<ul>
<li>⚠️有的网点不能现场拿卡,卡片会在 2-3 周后平邮寄给你,收信地址为你开户填写的住址</li>
<li>🆗通讯地址通常默认为身份证地址,如果身份证地址可收信件,则无需地址证明</li>
<li>➡️如果身份证地址不可用,可以用其他地址(❗️不可以是公司地址),但需提供地址证明</li>
<li>➡️地址证明可以使用印有你名字和地址的水电缴费单、信用卡账单(必须加盖正常公章。❗️有公章的电子账单打印出来也是不行的),有招行信用卡的话,直接去招行网点打印信用卡账单即可。打印前把你的信用卡账单地址改为你的住址</li>
</ul>
</li>
<li>📱开通手机的境外数据漫游,买一个流量包(支付宝 - 惠出境)或者运营商 App,想省钱也可以提前买流量卡,但要确保自己的<strong>常用手机号在开户时能收短信</strong>,这个手机号会作为银行预留手机号。</li>
<li>🤳在支付宝 - 出行,顶部城市改到香港,开通香港乘车码,即可刷码乘地铁,注意<strong>紫色闸机才能刷码进出站</strong></li>
<li>🐙可以下载一个「旅客八达通」,</li>
<li>📱提前下载安装以下 App,这里提供 iOS 直达链接:
<ul>
<li><a href="https://apps.apple.com/app/id1534534188">BOCHK</a>:<strong>开户必备</strong>,要先用这个 App 填资料。</li>
<li><a href="https://apps.apple.com/app/id1403690384">BoC Pay</a>:<strong>开户必备</strong>,这个是中银香港的支付服务,类似支付宝,平时消费大多可以用,估计是柜员的任务,开户时会默认会帮你开通这个 App。</li>
<li><a href="https://apps.apple.com/app/id1477150600">ZA Bank</a>:<strong>可选</strong>。如果想要多搞一张银行卡的话可以考虑,详见文末。</li>
<li><a href="https://apps.apple.com/app/id1505492952">旅客八达通</a>:<strong>可选</strong>。可以用这个 App 开通一张电子八达通(押金 50HKD,退卡手续费 11HKD),可用内地银行卡充值。虽然在港消费大多数地方能用支付宝,但八达通更好用一些。而且坐电车🚃、天星小轮⛴️只能现金/八达通。</li>
<li><a href="https://apps.apple.com/app/id592031984">富途牛牛</a>:<strong>可选</strong>。如果需要开户炒股的话可以考虑,下文会说</li>
<li><a href="https://apps.apple.com/app/id1463024118">盈立证券usmart</a>:<strong>可选</strong>。同上</li>
</ul>
</li>
</ul>
<p><img src="https://s2.loli.net/2023/03/26/CmpRzfnQb1akBlX.jpg" alt="本文提及的App"></p>
<h2 id="天时地利人和">天时地利人和</h2>
<p><img src="https://s2.loli.net/2023/03/26/7dTmtXqaiYVse81.jpg" alt="中银香港网点排号"></p>
<h3 id="网点营业时间">网点营业时间</h3>
<ul>
<li>🈺️工作日 9:00-17:00,🈺️周六营业时间 9:00-13:00,♨️周日休息。</li>
<li>👥网红网点工作日 8 点就已经有人排队了,其他网点人不多应该就还好,偏一点的网点甚至无需排队。周末赴港旅客多,不出意外要排队办理。</li>
<li>⏱️中银香港的网点还没有像内地那样的智能柜机,开户业务全都需要柜员在电脑上填表操作才能完成,所以完成一个开户至少需要 20-40min,一个网点最多 4 个开户柜台(可能还要办其他业务),所以一天办不了几个人。</li>
</ul>
<h3 id="网点选择">网点选择</h3>
<ul>
<li>🔥中港城分行:就在西九龙站附近,<strong>可以现场拿卡</strong>,但是人巨多,听说 8 点拿号下午 14 点才能轮到</li>
<li>💭尖沙咀东分行:位于九龙尖沙咀,半岛中心商场旁,据传<strong>可以现场拿卡</strong>,也是人巨多,开门就发完当天的号了,交通也不是很方便,港铁出站还要走一段。</li>
<li>💭金华街分行:位于香港岛筲箕湾。<strong>无法现场拿卡</strong>,因为地点比较偏人很少,工作日中午 13 点到直接取号就能办几乎不用排队。可以乘坐终点站为筲箕湾的有轨电车,终点站下来就能看到,或者港铁坐到【筲箕湾】站。</li>
<li>✅奥海城分行:位于九龙奥海城二期商场中,<strong>无法现场拿卡</strong>,需邮寄卡片,下卡容易,但也是网红网点,工作日必须开门前就去排队,否则没戏。工作日早点去 8:30 前拿号 11 点前应该能办完(我在这个网点办理的,下面教程以这个为例)</li>
</ul>
<h3 id="现场拿卡是否必要">现场拿卡是否必要</h3>
<p>不是所有网点都有现成的卡片,所以大多数网点只能开户后由总行完成制卡,邮寄给你。至于你是否需要现场拿卡,可以参考这几点:</p>
<ul>
<li>🆗开户<strong>当天就可以正常使用网银、手机银行等功能,也可用账号在 ATM 存取款</strong>,所以不能现场拿卡<strong>影响不大</strong>。</li>
<li>💳邮寄的卡片上有你的名字,<strong>现场拿卡的卡片上没有名字</strong>,一些特殊的用卡场景可能无法使用没有名字的卡片。</li>
<li>✉️邮寄卡片默认是平邮,查不到任何邮寄进度,<strong>可能会寄丢</strong>,如果你不想寄平邮,可以在完成开户当天登陆 BOCHK app 联系客服修改为挂号信或者快递寄送。</li>
<li>✉️如果超过 1 个月未收到卡片,可以打电话给客服寄挂号信(30HKD)或 快递(100-300HKD)补寄。</li>
</ul>
<p>ps. 关于平邮寄卡,这里有个小技巧:由于众所周知的原因现在很多小区已经没有信箱了,这种情况邮政不会投递,而是直接退信。你可以在开户后回家附近找一个邮局,给自己开户时的地址寄一封挂号信,信封上写上电话号码。好心的邮政小哥在投递时会打电话给你(因为挂号信要求确认妥投),你可以让邮政小哥帮你留意一下近两周从香港寄给你的平邮信件,到时候联系你。</p>
<h3 id="开户沟通">开户沟通</h3>
<p>通常在开户的时候,柜员会核实开户资料和开户必要性,可能会涉及以下问题:</p>
<ol>
<li>任职的公司、职位、月收入?如实回答即可</li>
<li>开户目的为何?这个被问到的概率比较大</li>
</ol>
<ul>
<li>一般回答投资理财即可,如果是投资港股为目的,可能会被追问是否有证券交易经验,并可能要求出示证券账户证明或流水,可以直接打开内地的证券账户 App 给对方看一眼即可。</li>
<li>如果还没有购买保险,就不要说自己有保险需要,否则可能会被要求出示保单。当然如果已经买了的话,直接拿着保单去办卡,柜员看到可能就直接跳过该问题了😆</li>
<li>🙅♂️千万不要说自己办卡是为了换汇、消费使用,因为该目的不够充分,不能证明开户的必要性。毕竟现在内地换汇以及香港消费时支持的支付方式已经足够多,完全可以不需要银行卡。</li>
</ul>
<ol start="3">
<li>是否在内地担任政治相关职位?如果你回答是,大概率应该被拒吧哈哈哈🤣</li>
</ol>
<h2 id="行动攻略">行动攻略</h2>
<h3 id="通关赴港">通关赴港</h3>
<p>🕢07:20 福田地铁站出站</p>
<p>🕢07:38 福田站高铁发车</p>
<ul>
<li>🚄 开车前 15 min 开始检票,福田地铁站出站后去高铁候车区还有点距离,走到候车区要 5-10min,预留好时间。</li>
<li>🤳 在高铁上连上 Wi-Fi,扫描海关小程序报关,截图海关二维码</li>
<li>📱 打开支付宝 - 惠出境,领取最优汇率,7d 内在香港用支付宝支付汇率会更美丽!</li>
</ul>
<p>🕖07:53 到达西九龙,按指示牌出站、过境出关</p>
<ul>
<li>🛃先刷海关二维码</li>
<li>🛂用通行证内地出境</li>
<li>🛂用通行证香港入境</li>
<li>🚇刷身份证出站</li>
</ul>
<h3 id="前往奥海城分行">前往奥海城分行</h3>
<p>🕗08:05 港铁【柯士甸站】上车</p>
<ul>
<li>🚇屯马线 - 屯门方向 1 站,【南昌】站下车</li>
<li>🚇对面月台换乘东铁线 - 香港方向 1 站,【奥运】站下车</li>
<li>🚇【奥运】站 C 口出站</li>
</ul>
<p>🕣08:20 出站</p>
<ul>
<li>🪧 出站后顺着指示牌前往奥海城二期方向</li>
<li>👀 进入奥海城商城,看到商场内的广场时,左侧有上、下楼两台扶梯,右侧有一台下楼扶梯。</li>
<li>👀 选择最左侧扶梯上楼,然后会看到一家建设银行,继续往左侧方向走几十米就到了【中国银行(香港)】奥海城分行网点</li>
</ul>
<p>🕣08:25 到达银行网点,在最左侧门面排队(门口有个排队进度的架子,上面写着 A001 之类的),通常工作日这个时间点应该可以排在前三位。排队的这时候,可以按下面的教程把券商账户、ZA Bank 完成开户。</p>
<p>🕣08:37 我去办的当天这时候已经排了 7 个人了</p>
<p>🕘08:50 打开 BOCHK App,扫描柜员提供的二维码填写信息,要填很多大概要 10min,App 拍摄识别身份证时直接把身份证放在地上会快很多!</p>
<p>🕘09:40 完成开户,听说我办的时候当天的排号已经发完了🤯</p>
<h2 id="券商账户开户">券商账户开户</h2>
<ul>
<li>1️⃣<a href="https://apps.apple.com/app/id592031984">富途牛牛</a>:富途就不多介绍了,但是 App 要求内地人员只能 GPS 定位在 HK 才能开户。在银行门口排队的时候,连上银行的 Wi-Fi,提交资料申请开户即可。首次入金要求至少 1w HKD。</li>
<li>2️⃣<a href="https://apps.apple.com/app/id1463024118">盈立证券usmart</a>:这个好像可以在内地直接开户,未上市的小券商,佣金比富途低。用我的 <a href="https://www.usmart.hk/webapp/open-account/apply.html?ICode=6bqq&Avatar=&n=umuu135#/register">邀请链接</a> 或者邀请码:<code>6bqq</code> 注册,我们都可以获得一堆优惠券。</li>
</ul>
<h2 id="za-bank">ZA Bank</h2>
<p><img src="https://s2.loli.net/2023/03/26/4XdR8rzmTGpewc2.jpg" alt="ZA Card"></p>
<p>这里提一嘴 ZA Bank 银行卡。
众安银行是一个互联网银行、虚拟银行。🈚️无营业网点,基本上所有业务只需通过 App 就能完成。</p>
<ul>
<li>1️⃣众安的卡本质上是一张 visa 借记卡,<strong>无存款门槛,无账户管理费</strong></li>
<li>2️⃣<strong>开户门槛低</strong>,IP 和 GPS 在 HK 即可 App 注册开户</li>
<li>3️⃣<strong>无法现金存款</strong>,只能其他银行卡(目前只支持 HK 银行卡)转账过去,收款无手续费。除了存款,其他使用上与普通银行卡无异,在<strong>全港 ATM 取现免手续费</strong></li>
<li>4️⃣可免费申请实体卡片 ZA Card,自定义卡号后 6 位数字(2023.6.1 之后需要自付卡片邮费 25HKD)</li>
<li>5️⃣刷卡消费有积分和优惠,可以配合已经开好的其他港卡使用</li>
</ul>
<h2 id="用卡事项">用卡事项</h2>
<p>前面说到中行的卡用起来省心一点,无非主要就是成本问题,一般来说主要操作是转账,这里大概整理一下常用的用卡场景和费用。</p>
<h3 id="内地银行卡收费">内地银行卡收费</h3>
<ul>
<li>
<p>如果你有内地中国银行的储蓄卡,可以<strong>使用手机银行从内地中银卡转帐到中银香港的同名账户,免手续费</strong>:</p>
<ul>
<li>跨境汇款手续费:汇款金额的 1‰,最低人民币 50CNY/笔,最高人民币 260CNY/笔。</li>
<li>电讯费:港澳台地区 80CNY/笔,非港澳台地区 150CNY/笔。</li>
<li>通过手机银行向境外中行汇款时,跨境汇款手续费及电讯费全免;通过手机银行向境外他行汇款时,跨境汇款手续费及电讯费在柜台收费的基础上进行9折优惠。</li>
<li>其他费用详见:<a href="https://www.bankofchina.com/custserv/fd5/">中国银行网站_服务价目</a></li>
</ul>
</li>
<li>
<p>跨行的跨境转账 / 汇款,每个银行收费不一样,这里就不一一列举了,各位各显神通吧。</p>
</li>
</ul>
<h3 id="中银香港银行卡收费">中银香港银行卡收费</h3>
<p>下面是中银香港的主要收费条目,其他没提到的费用可以看完整版:<a href="https://www.bochk.com/sc/servicecharge.html">一般银行服务收费 | 中国银行(香港)有限公司</a></p>
<table>
<thead>
<tr>
<th>项目</th>
<th>说明</th>
<th>收费</th>
</tr>
</thead>
<tbody>
<tr>
<td>储蓄账户</td>
<td>管理费</td>
<td>免费,无最低存款限制</td>
</tr>
<tr>
<td>本地转账</td>
<td>特快转账(RTGS/ CHATS)到本行账户</td>
<td>免费</td>
</tr>
<tr>
<td>本地转账</td>
<td>特快转账(RTGS/ CHATS)到其他银行</td>
<td>网上银行:免费<br/>柜台转账:180HKD/笔</td>
</tr>
<tr>
<td>转数快(FPS)</td>
<td>转帐到本行账户</td>
<td>免费</td>
</tr>
<tr>
<td>转数快(FPS)</td>
<td>转帐到其他银行</td>
<td>100wHKD 内免费</td>
</tr>
<tr>
<td>转数快(FPS)</td>
<td>查询、退回的手续费</td>
<td>150HKD/笔</td>
</tr>
<tr>
<td>自动转账</td>
<td>设置/修改/退款/再次执行</td>
<td>70-150HKD 不等</td>
</tr>
<tr>
<td>存款/取现</td>
<td>港币</td>
<td>无手续费</td>
</tr>
<tr>
<td>存款/取现</td>
<td>人民币/外币</td>
<td>只能在柜台办理,有每日限额</td>
</tr>
<tr>
<td>汇出汇款</td>
<td>普通电汇</td>
<td>电子渠道:65HKD/笔<br/>柜台渠道:240HKD/笔</td>
</tr>
<tr>
<td>汇出汇款</td>
<td>电汇:"中银快汇"</td>
<td>电子渠道:免费<br/>柜台渠道:240HKD/笔</td>
</tr>
<tr>
<td>汇出汇款</td>
<td>BoC Pay 跨境汇款</td>
<td>按汇款金额1%(港币)(每次最低收费HKD20,最高收费HKD60</td>
</tr>
<tr>
<td>汇入汇款</td>
<td>将款项存入本行户口</td>
<td>汇款金额<500HKD:免费<br/>汇款金额>500HKD:60HKD/笔</td>
</tr>
<tr>
<td>补卡</td>
<td></td>
<td>50HKD</td>
</tr>
<tr>
<td>证券账户*</td>
<td>账户保管費</td>
<td>150HKD/半年</td>
</tr>
<tr>
<td>证券账户*</td>
<td>佣金及其他费用</td>
<td><a href="https://www.bochk.com/dam/investment/sec_fee_sc.pdf">收费详情</a></td>
</tr>
</tbody>
</table>
<p>*以投资理财 / 炒股为理由开户时,通常会帮你一并开通中国银行自己的证券账户。如果没有持仓 / 交易,看起来好像是可以免账户保管費的。</p>
<hr>
<p>参考链接:
<a href="https://blog.forecho.com/coming-to-hong-kong-to-get-a-hong-kong-bank-card.html">《来香港办香港银行卡 - forecho's Blog》</a></p>
《深入剖析Kubernetes》学习笔记(一):容器技术
https://acuario.xyz/posts/in-depth-analysis-of-kubernetes-container/
2023-09-27T18:25:39+00:00
2022-10-29T17:32:45+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="docker--kubernetes-背景">Docker & Kubernetes 背景</h2>
<ul>
<li>传统 Paas 项目如 Cloud Foundry 最核心的组件就是一套应用的打包和分发机制。Cloud Foundry 为每种主流编程语言都定义了一种打包格式,用户把应用的可执行文件和启动脚本打进一个压缩包内上传后交给服务商通过调度器选择一个可以运行这个应用的虚拟机,然后通知这个机器上的 Agent 把应用压缩包下载下来启动。</li>
<li>Docker 镜像是直接由一个完整操作系统的所有文件和目录构成的,所以这个压缩包里的内容跟你本地开发和测试环境用的操作系统是完全一样的。这种机制直接打包了应用运行所需要的整个操作系统,从而保证了本地环境和云端环境的高度一致,避免了用户通过「试错」来匹配两种不同运行环境之间差异的痛苦过程。</li>
<li>「编排」(Orchestration)在云计算行业里不算是新词汇,它主要是指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义、配置、创建、删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。容器时代,「编排」显然就是对 Docker 容器的一系列定义、配置和创建动作的管理。</li>
</ul>……
<h2 id="docker--kubernetes-背景">Docker & Kubernetes 背景</h2>
<ul>
<li>传统 Paas 项目如 Cloud Foundry 最核心的组件就是一套应用的打包和分发机制。Cloud Foundry 为每种主流编程语言都定义了一种打包格式,用户把应用的可执行文件和启动脚本打进一个压缩包内上传后交给服务商通过调度器选择一个可以运行这个应用的虚拟机,然后通知这个机器上的 Agent 把应用压缩包下载下来启动。</li>
<li>Docker 镜像是直接由一个完整操作系统的所有文件和目录构成的,所以这个压缩包里的内容跟你本地开发和测试环境用的操作系统是完全一样的。这种机制直接打包了应用运行所需要的整个操作系统,从而保证了本地环境和云端环境的高度一致,避免了用户通过「试错」来匹配两种不同运行环境之间差异的痛苦过程。</li>
<li>「编排」(Orchestration)在云计算行业里不算是新词汇,它主要是指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义、配置、创建、删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。容器时代,「编排」显然就是对 Docker 容器的一系列定义、配置和创建动作的管理。</li>
</ul>
<ul>
<li>大数据所关注的计算密集型离线业务,其实并不像常规的 Web 服务那样适合用容器进行托管和扩容,也没有对应用打包的强烈需求,所以 Hadoop、Spark 等项目到现在也没在容器技术上投下更大的赌注。</li>
<li>Mesosphere 公司发布了一个名为 Marathon 的项目,而这个项目很快就成为了 Docker Swarm 的一个有力竞争对手。Mesos 社区却拥有一个独特的竞争力:超大规模集群的管理经验。Mesos+Marathon 的组合实际上进化成了一个高度成熟的 PaaS 项目,同时还能很好地支持大数据业务。</li>
<li>Mesosphere 公司不失时机地提出了一个名叫「DC/OS」(数据中心操作系统)的口号和产品,旨在使用户能够像管理一台机器那样管理一个万级别的物理机集群,并且使用 Docker 容器在这个集群里自由地部署应用。这对很多大型企业来说具有着非同寻常的吸引力。</li>
<li>2015 年 6 月 22 日,由 Docker 公司牵头,CoreOS、Google、RedHat 等公司共同宣布,Docker 公司将 Libcontainer 捐出,并改名为 RunC 项目,交由一个完全中立的基金会管理,然后以 RunC 为依据,大家共同制定一套容器和镜像的标准和规范。这套标准和规范,就是 OCI( Open Container Initiative )。OCI 的提出,意在将容器运行时和镜像的实现从 Docker 项目中完全剥离出来。这样做,一方面可以改善 Docker 公司在容器技术上一家独大的现状,另一方面也为其他玩家不依赖于 Docker 项目构建各自的平台层能力提供了可能。尽管 Docker 是 OCI 的发起者和创始成员,它却很少在 OCI 的技术推进和标准制定等事务上扮演关键角色,也没有动力去积极地推进这些所谓的标准。这也正是迄今为止 OCI 组织效率持续低下的根本原因。</li>
<li>Kubernetes 项目的基础特性,并不是几个工程师突然「拍脑袋」想出来的东西,而是 Google 公司在容器化基础设施领域多年来实践经验的沉淀与升华。这,正是 Kubernetes 项目能够从一开始就避免同 Swarm 和 Mesos 社区同质化的重要手段。</li>
<li>Mesos 社区与容器技术的关系,更像是「借势」,而不是这个领域真正的参与者和领导者,加上它所属的 Apache 社区固有的封闭性,导致了 Mesos 社区虽然技术最为成熟,却在容器编排领域鲜有创新。</li>
<li>Kubernetes 项目让人耳目一新的设计理念和号召力,很快就构建出了一个与众不同的容器编排与管理的生态。</li>
<li>从 API 到容器运行时的每一层,Kubernetes 项目都为开发者暴露出了可以扩展的插件机制,鼓励用户通过代码的方式介入 Kubernetes 项目的每一个阶段。Kubernetes 项目的这个变革的效果立竿见影,很快在整个容器社区中催生出了大量的、基于 Kubernetes API 和扩展接口的二次创新工作。</li>
</ul>
<h2 id="容器基础">容器基础</h2>
<ul>
<li>容器其实是一种沙盒技术,应用与应用之间因为有了边界而不至于相互干扰。</li>
<li>容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个「边界」。</li>
<li>对于 Docker 等大多数 Linux 容器来说,Cgroups 技术是用来制造约束的主要手段,而 Namespace 技术则是用来修改进程视图的主要方法。</li>
</ul>
<h3 id="容器隔离">容器隔离</h3>
<ul>
<li>
<p>在 Linux 系统中创建进程的系统调用是 <code>clone()</code>,比如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">pid</span> <span class="o">=</span> <span class="nf">clone</span><span class="p">(</span><span class="n">main_function</span><span class="p">,</span> <span class="n">stack_size</span><span class="p">,</span> <span class="n">SIGCHLD</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>该系统调用就会创建一个新的进程,并且返回它的进程号 PID。在执行 <code>clone()</code> 系统调用创建一个新进程时,可以指定 <code>CLONE_NEWPID</code> 参数。这样创建的进程将会「看到」一个全新的进程空间,在这个进程空间里,它的 PID 是 1。在宿主机真实的进程空间里,这个进程的 PID 还是真实的数值,比如 100:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">pid</span> <span class="o">=</span> <span class="nf">clone</span><span class="p">(</span><span class="n">main_function</span><span class="p">,</span> <span class="n">stack_size</span><span class="p">,</span> <span class="n">CLONE_NEWPID</span> <span class="o">|</span> <span class="n">SIGCHLD</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>多次执行上面的 <code>clone()</code> 调用,这样就会创建多个 PID Namespace,而每个 Namespace 里的应用进程,都会认为自己是当前容器里的第 1 号进程,它们既看不到宿主机里真正的进程空间,也看不到其他 PID Namespace 里的具体情况。除了 PID Namespace,Linux 操作系统还提供了 Mount、UTS、IPC、Network 和 User 这些 Namespace,用来对各种不同的进程上下文进行「障眼法」操作。</p>
<ul>
<li>eg.<code>Mount Namespace</code>:用于让被隔离进程只看到当前 Namespace 里的挂载点信息。</li>
<li>eg.<code>Network Namespace</code>:用于让被隔离进程看到当前 Namespace 里的网络设备和配置。</li>
</ul>
</li>
<li>
<p>Docker 容器实际上是在创建容器进程时,指定了这个进程所需要启用的一组 Namespace 参数。这样,容器就只能「看」到当前 Namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。跟真实存在的虚拟机不同,在使用 Docker 的时候,并没有一个真正的「Docker 容器」运行在宿主机里面。Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数。这些进程会觉得自己是各自 PID Namespace 里的第 1 号进程,只能看到各自 <code>Mount Namespace</code> 里挂载的目录和文件,只能访问到各自 Network Namespace 里的网络设备,就仿佛运行在一个个「容器」里面,与世隔绝。</p>
</li>
<li>
<p>用户运行在容器里的应用进程,跟宿主机上的其他进程一样,都由宿主机操作系统统一管理,只不过这些被隔离的进程拥有额外设置过的 Namespace 参数。容器并不直接运行在 Docker 上,Docker 只是辅助建立隔离环境,让容器基于 Linux 操作系统运行。Docker 项目在这里扮演的角色,更多的是旁路式的辅助和管理工作。</p>
</li>
<li>
<p>容器优点:</p>
<ul>
<li>使用虚拟化技术作为应用沙盒,就必须要由 Hypervisor 来负责创建虚拟机,这个虚拟机是真实存在的,并且它里面必须运行一个完整的 Guest OS 才能执行用户的应用进程。这就不可避免地带来了额外的资源消耗和占用。相比之下,容器化后的用户应用,却依然还是一个宿主机上的普通进程,这就意味着这些因为虚拟化而带来的性能损耗都是不存在的;</li>
<li>使用 Namespace 作为隔离手段的容器并不需要单独的 Guest OS,这就使得容器额外的资源占用几乎可以忽略不计。</li>
</ul>
</li>
<li>
<p>容器缺点:</p>
<ul>
<li>容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。eg. 无法在宿主机中运行其他版本内核的系统容器</li>
<li>在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的。eg. 如果你的容器中的程序使用 <code>settimeofday(2)</code> 系统调用修改了时间,整个宿主机的时间都会被随之修改</li>
<li>容器给应用暴露出来的攻击面是相当大的,应用「越狱」的难度自然也比虚拟机低得多。</li>
<li><code>/proc</code> 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:<code>/proc</code> 文件系统不了解 Cgroups 限制的存在。在生产环境中,这个问题必须进行修正,否则应用程序在容器里读取到的 CPU 核数、可用内存等信息都是宿主机上的数据,这会给应用的运行带来非常大的困惑和风险。这也是在企业中,容器化应用碰到的一个常见问题,也是容器相较于虚拟机另一个不尽如人意的地方。</li>
</ul>
</li>
</ul>
<h3 id="容器限制">容器限制</h3>
<ul>
<li>Linux 操作系统内核之中为资源隔离提供了三种技术:
<ul>
<li>namespace:2002 年从 Linux 2.4.19 开始出现,用来创建独立的文件系统、主机名、进程号、网络等资源空间,实现系统全局资源和进程局部资源的隔离。</li>
<li>cgroup:2008 年从 Linux 2.6.24 开始出现,它的全称是 Linux Control Group,用来实现对进程的 CPU、内存等资源的优先级和配额限制。</li>
<li>chroot:在 1979 年的 UNIX V7 就已经出现了,它可以更改进程的根目录,也就是限制访问文件系统。</li>
</ul>
</li>
<li>对 Docker 项目来说,它最核心的原理实际上就是创建一个用户进程:
<ul>
<li>启用 Linux Namespace 配置。</li>
<li>设置指定的 Cgroups,Linux Control Group) 参数。</li>
<li>切换进程的根目录(chroot,Change Root)。</li>
</ul>
</li>
<li>容器是一个创建时指定了 namespace 的进程,并且启动参数里设置了 cpu、内存的限制,使用的文件系统目录也被提前设置,挂载到了其他的目录(这个就是镜像)。所以容器没有像虚拟机一样虚拟出内核等,容器使用的是宿主机的内核。</li>
</ul>
<h4 id="cgroup">cgroup</h4>
<ul>
<li>
<p>一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。这也是容器技术中一个非常重要的概念,即:<strong>容器是一个「单进程」模型</strong>。</p>
</li>
<li>
<p>Linux Cgroups 的全称是 <strong>Linux Control Group</strong>,它是 Linux 内核中用来为进程设置资源限制的一个重要功能。其主要作用是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。</p>
</li>
<li>
<p>对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。</p>
</li>
<li>
<p>用户执行 docker run 时,可以通过指定参数来控制对应的资源文件配额:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ docker run -it --cpu-period<span class="o">=</span><span class="m">100000</span> --cpu-quota<span class="o">=</span><span class="m">20000</span> ubuntu /bin/bash
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h4 id="chroot">chroot</h4>
<ul>
<li><code>chroot</code> (change root file system) 可以改变进程的根目录到你指定的位置。对于被 chroot 的进程来说,它并不会感受到自己的根目录已经被「修改」成 $HOME/test 了。</li>
</ul>
<h4 id="namespace">namespace</h4>
<ul>
<li><code>Mount Namespace</code> 正是基于对 chroot 的不断改良才被发明出来的,它也是 Linux 操作系统里的第一个 Namespace。</li>
<li><code>Mount Namespace</code> 跟其他 Namespace 的使用略有不同的地方:它对容器进程视图的改变,一定是伴随着挂载操作(mount)才能生效。</li>
<li>在容器进程启动之前重新挂载它的整个根目录「/」。而由于 <code>Mount Namespace</code> 的存在,这个挂载对宿主机不可见,所以容器进程就可以在里面随便折腾了。</li>
</ul>
<h3 id="容器原理">容器原理</h3>
<ul>
<li>
<p>Docker 使用包括但不限于以下文件系统进行目录联合挂载:</p>
<ul>
<li><code>overlayfs</code> 为目前最新的 docker 版本中 ubuntu 和 centos 系统默认使用的文件系统。</li>
<li><code>AuFS</code> 常用于 Ubuntu。</li>
<li><code>device mapper</code> 常用于 CentOS。</li>
<li><code>btrfs</code> 常用于 SUSE。</li>
<li><code>vfs</code> 常用于 solaris 系统。</li>
<li><code>zfs</code> 常用于 solaris 系统。</li>
</ul>
</li>
<li>
<p><code>Union File System</code> 也叫 <code>UnionFS</code>,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下。</p>
</li>
<li>
<p><code>AuFS</code>(<code>Advance UnionFS</code>)是对 Linux 原生 <code>UnionFS</code> 的重写和改进。</p>
</li>
<li>
<p>为了删除操作,<code>AuFS</code> 会在可读写层创建一个 whiteout 文件,把只读层里的文件「遮挡」起来。实际上是在可读写层创建一个名为。wh.xxx 的文件。这样,当这两个层被联合挂载之后,该文件就会被。wh.xxx 遮挡起来,消失了。这个功能就是「ro+wh」的挂载方式,即只读+whiteout 的含义。</p>
</li>
<li>
<p><code>docker exec</code> 的实现原理是一个名叫 <code>setns()</code> 的 Linux 系统调用。下例展示的是通过 <code>open()</code> 系统调用打开了指定的 Namespace 文件,并把这个文件的描述符 fd 交给 <code>setns()</code> 使用。在 <code>setns()</code> 执行后,当前进程就加入了这个文件对应的 Linux Namespace 当中了。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">fd</span> <span class="o">=</span> <span class="nf">open</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">O_RDONLY</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="nf">setns</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="nf">errExit</span><span class="p">(</span><span class="s">"setns"</span><span class="p">);</span> <span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>我们通常会在容器的根目录下挂载一个完整操作系统的文件系统,比如 Ubuntu16.04 的 ISO。容器启动之后在容器里执行 <code>ls /</code> 可以查看根目录下的内容,即 Ubuntu 16.04 的所有目录和文件。而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的「容器镜像」,也叫作:rootfs(根文件系统)。</p>
</li>
<li>
<p>当容器进程被创建之后,尽管开启了 <code>Mount Namespace</code>,但是在它执行 <code>chroot</code>(或者 pivot_root)之前,容器进程一直可以看到宿主机上的整个文件系统。所以只需要在 rootfs 准备好之后,在执行 <code>chroot</code> 之前,把 Volume 指定的宿主机目录(比如 <code>/home</code> 目录),挂载到指定的容器目录(比如 <code>/test</code> 目录)在宿主机上对应的目录(即 <code>/var/lib/docker/aufs/mnt/[可读写层 ID]/test</code>)上,这个 Volume 的挂载工作就完成了。由于执行这个挂载操作时,「容器进程」已经创建了,也就意味着此时 <code>Mount Namespace</code> 已经开启了。所以,这个挂载事件只在这个容器里可见。宿主机是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被 Volume 打破。</p>
</li>
<li>
<p>Volume 使用到的挂载技术,就是 Linux 的绑定挂载(bind mount)机制。它的主要作用就是,允许你将一个目录或者文件,而不是整个设备,挂载到一个指定的目录上。并且,这时你在该挂载点上进行的任何操作,只是发生在被挂载的目录或者文件上,而原挂载点的内容则会被隐藏起来且不受影响。</p>
</li>
<li>
<p>容器的镜像操作,比如 <code>docker commit</code>,都是发生在宿主机空间的。而由于 <code>Mount Namespace</code> 的隔离作用,宿主机并不知道这个绑定挂载的存在。所以,在宿主机看来,容器中可读写层的 <code>/test</code> 目录(<code>/var/lib/docker/aufs/mnt/[可读写层 ID]/test</code>)始终是空的。不过,由于 Docker 一开始还是要创建 <code>/test</code> 这个目录作为挂载点,所以执行了 <code>docker commit</code> 之后,你会发现新产生的镜像里,会多出来一个空的 <code>/test</code> 目录。毕竟,新建目录操作,又不是挂载操作,<code>Mount Namespace</code> 对它可起不到「障眼法」的作用。即宿主机执行 <code>docker commit</code> 不会把挂载过的目录打包,因为这个目录在宿主机上来看,就是一个空文件夹</p>
</li>
</ul>
<h2 id="kubernetes-的本质">Kubernetes 的本质</h2>
<ul>
<li>一个「容器」,实际上是一个由 Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境。</li>
<li>容器可以分为两个部分:
<ul>
<li>一组联合挂载在 <code>/var/lib/docker/aufs/mnt</code> 上的 <code>rootfs</code>,称为「容器镜像」(Container Image),是<strong>容器的静态视图</strong>;</li>
<li>一个由 Namespace+Cgroups 构成的隔离环境,称为「容器运行时」(Container Runtime),是<strong>容器的动态视图</strong>。</li>
</ul>
</li>
<li>Kubernetes 项目最主要的设计思想是从更宏观的角度,以统一的方式来定义任务之间的各种关系,并且为将来支持更多种类的关系留有余地。</li>
<li>在常规环境下,这些应用往往会被直接部署在同一台机器上,通过 Localhost 通信,通过本地磁盘目录交换文件。而在 Kubernetes 项目中,这些容器则会被划分为一个「<strong>Pod</strong>」,Pod 里的容器共享同一个 Network Namespace、同一组数据卷,从而达到高效率交换信息的目的。</li>
<li>Kubernetes 给 Pod 绑定一个 <strong>Service</strong> 服务,而 Service 服务声明的 IP 地址等信息是「终生不变」的。这个 Service 服务的主要作用,就是作为 Pod 的代理入口(Portal),从而代替 Pod 对外暴露一个固定的网络地址。</li>
<li>Kubernetes 项目提供了一种叫作 Secret 的对象,它其实是一个保存在 Etcd 里的键值对数据。把 Credential 信息以 Secret 的方式存在 Etcd 里,Kubernetes 就会在指定的 Pod(比如,Web 应用的 Pod)启动时,自动把 Secret 里的数据以 Volume 的方式挂载到容器里。Web 应用可以通过这样的方式实现数据库的访问。</li>
<li>Kubernetes 定义了新的、基于 Pod 改进后的对象,如:
<ul>
<li>Job,用来描述一次性运行的 Pod(比如,大数据任务)</li>
<li>DaemonSet,用来描述每个宿主机上必须且只能运行一个副本的守护进程服务;</li>
<li>CronJob,则用于描述定时任务等等。</li>
</ul>
</li>
<li>Kubernetes 项目推崇的使用方法是所谓的「声明式 API」。这种 API 对应的「编排对象」和「服务对象」,都是 Kubernetes 项目中的 API 对象(API Object)。这是 Kubernetes 最核心的设计理念:
<ul>
<li>通过一个「编排对象」,比如 Pod、Job、CronJob 等,来描述你试图管理的应用;</li>
<li>为这些「编排对象」定义一些「服务对象」,比如 Service、Secret、Horizontal Pod Autoscaler(自动水平扩展器)等,从而实现具体的平台级功能。</li>
</ul>
</li>
</ul>
<h2 id="kubernetes-配置">Kubernetes 配置</h2>
<p>示例:定义一个符合下属条件的 Pod:</p>
<ul>
<li>容器副本个数 (<code>spec.replicas</code>) 为 2</li>
<li>Pod 里只有一个容器镜像(<code>spec.containers.image</code>)为 <code>nginx:1.7.9</code></li>
<li>容器监听端口(<code>containerPort</code>)是 80</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx-deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">selector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">replicas</span><span class="p">:</span><span class="w"> </span><span class="m">2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">containers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nginx:1.8</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="m">80</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">volumeMounts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="s2">"/usr/share/nginx/html"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx-vol</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx-vol</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">emptyDir</span><span class="p">:</span><span class="w"> </span>{}<span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>Pod 就是 Kubernetes 世界里的「应用」;而一个应用,可以由多个容器组成。</p>
</li>
<li>
<p>使用一种 API 对象(eg. Deployment)管理另一种 API 对象(eg. Pod)的方法,在 Kubernetes 中,叫作「控制器」模式(controller pattern)。</p>
</li>
<li>
<p>每一个 API 对象都有一个叫作 Metadata 的字段,这个字段就是 API 对象的「标识」,即元数据,它也是我们从 Kubernetes 里找到这个对象的主要依据。这其中最主要使用到的字段是 Labels。</p>
</li>
<li>
<p>Labels 就是一组 key-value 格式的标签。而像 Deployment 这样的控制器对象,就可以通过这个 Labels 字段从 Kubernetes 中过滤出它所关心的被控制对象。比如,在上面这个 YAML 文件中,Deployment 会把所有正在运行的、携带 <code>app: nginx</code> 标签的 Pod 识别为被管理的对象,并确保这些 Pod 的总数严格等于两个。过滤规则定义在 Deployment 的 <code>spec.selector.matchLabels</code> 字段。一般称之为:Label Selector。</p>
</li>
<li>
<p>与 Labels 格式、层级完全相同的字段叫 Annotations,它专门用来携带 key-value 格式的内部信息。所谓内部信息,指的是对这些信息感兴趣的,是 Kubernetes 组件本身,而不是用户。</p>
</li>
<li>
<p>一个 Kubernetes 的 API 对象的定义,大多可以分为 Metadata 和 Spec 两个部分。前者存放的是这个对象的元数据,对所有 API 对象来说,这一部分的字段和格式基本上是一样的;而后者存放的,则是属于这个对象独有的定义,用来描述它所要表达的功能。</p>
</li>
<li>
<p>使用 kubectl apply 命令,来统一进行 Kubernetes 对象的创建和更新操作。这样的操作方法,是 Kubernetes「声明式 API」所推荐的使用方法。Kubernetes 会根据 YAML 文件的内容变化自动进行具体的处理。用户只需围绕着可以版本化管理的 YAML 文件,而不是「行踪不定」的命令行进行协作,从而大大降低开发人员和运维人员之间的沟通成本:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ kubectl apply -f nginx-deployment.yaml
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>Kubernetes 项目通过这些 YAML 文件,就保证了应用的「部署参数」在开发与部署环境中的一致性。而当应用本身发生变化时,开发人员和运维人员可以依靠容器镜像来进行同步;当应用部署参数发生变化时,这些 YAML 文件就是他们相互沟通和信任的媒介。</p>
</li>
</ul>
《功利主义》读书笔记
https://acuario.xyz/others/utilitarianism-clip/
2023-09-27T18:25:39+00:00
2022-08-11T00:02:27+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>译者序 第 III 页<br>
现代西方社会思潮的主流是自由主义,而在自由主义的内部,一般认为又可分为三大派别,即自由平等主义、自由至上主义与功利主义。不过在笔者看来,从方法论的角度说,最有影响的思想流派只有两个,一个是发源于古代自然法学的契约论学派,而另一个就是功利主义学派。
当代自由主义契约论学派的基本观点是,合乎道德的行为或制度应当符合正义的原则,而所谓正义,简要地说就是尊重或者不侵犯个人的基本人权。如果要问其理由或根据,那么这个学派的基本方法论依据是,处于平等地位的人们会一致同意这一点,或者人的天启理性会告诉你这一点;换言之,因为人的理性都是相同的,所以我们可以诉诸每个人的同意,而诉诸人们的一致同意差不多也就相当于诉诸人的理性。如果再要追根究底,那么还可以顺着天启理性追溯到自然法或上帝那儿。</p>
<hr>
<p>译者序 第 V 页<br>
功利主义之所以对当代的人类思想具有更大的影响,不仅是因为其伦理学的基本观点极其简单,并且符合常人的理性——合乎道德的行为或制度应当能够促进“最大多数人的最大幸福”,更主要的是因为,通过“最大多数人的最大幸福”这一概念的不同解释或表述,如“公众幸福”、“社会功利”、“社会繁荣”乃至表示“效率”的各种标准如“帕雷托最优”、“GDP、“生产可能性边界”等等,功利主义不仅在政治领域构造了一种足以与自由主义契约论学派相抗衡的政治哲学和法哲学,而且在经济领域排除了所有其他的伦理学说而独自成为主流经济学的伦理框架。我们或许可以说,在现有的伦理学说中,功利主义是唯一能够奠定各门社会科学的伦理基础,从而为它们指明方向的伦理学说。</p>……
<p>译者序 第 III 页<br>
现代西方社会思潮的主流是自由主义,而在自由主义的内部,一般认为又可分为三大派别,即自由平等主义、自由至上主义与功利主义。不过在笔者看来,从方法论的角度说,最有影响的思想流派只有两个,一个是发源于古代自然法学的契约论学派,而另一个就是功利主义学派。
当代自由主义契约论学派的基本观点是,合乎道德的行为或制度应当符合正义的原则,而所谓正义,简要地说就是尊重或者不侵犯个人的基本人权。如果要问其理由或根据,那么这个学派的基本方法论依据是,处于平等地位的人们会一致同意这一点,或者人的天启理性会告诉你这一点;换言之,因为人的理性都是相同的,所以我们可以诉诸每个人的同意,而诉诸人们的一致同意差不多也就相当于诉诸人的理性。如果再要追根究底,那么还可以顺着天启理性追溯到自然法或上帝那儿。</p>
<hr>
<p>译者序 第 V 页<br>
功利主义之所以对当代的人类思想具有更大的影响,不仅是因为其伦理学的基本观点极其简单,并且符合常人的理性——合乎道德的行为或制度应当能够促进“最大多数人的最大幸福”,更主要的是因为,通过“最大多数人的最大幸福”这一概念的不同解释或表述,如“公众幸福”、“社会功利”、“社会繁荣”乃至表示“效率”的各种标准如“帕雷托最优”、“GDP、“生产可能性边界”等等,功利主义不仅在政治领域构造了一种足以与自由主义契约论学派相抗衡的政治哲学和法哲学,而且在经济领域排除了所有其他的伦理学说而独自成为主流经济学的伦理框架。我们或许可以说,在现有的伦理学说中,功利主义是唯一能够奠定各门社会科学的伦理基础,从而为它们指明方向的伦理学说。</p>
<hr>
<p>译者序 第 VIII 页<br>
边沁认为,感觉经验是包括道德知识在内的一切知识的最根本而又真实的基础,因此,伦理道德也不能不建立在为人类经验所认可的人的趋乐避苦的本性和自我利益的追求之基础上:“当我们对任何一种行为予以赞成或不赞成的时候,我们是看该行为是增多还是减少当事者的幸福。”当每个人都真正得到了自己的最大利益时,社会也就达到了“最大多数人的最大幸福”,因为“最大幸福原理”依赖于每个人的最大幸福之加总。于是,功利主义道德基本上就在于苦乐的计算。在边沁的理论中,开明利己主义与功利主义是一致的。</p>
<hr>
<p>译者序 第 IX 页<br>
功利主义道德在精神上是不同于西方传统道德的。西方传统道德的基本精神是建立在上帝信仰之上的克已和利他,是与追求个人利益相对立的。而功利主义道德的基本精神则在于日常经验对个人利益的肯定,在于与个人利益的一致;这种利益,可以称之为幸福,也可以称之为价值,可以称之为有用,也可称之为效用,它建立在普通人日常生活中所追求各种目的或目标之上,没有任何虚无缥缈和神圣之处。</p>
<hr>
<p>译者序 第 XII 页<br>
穆勒指出,功利主义并不反对自我牺牲,但反对把自我牺牲本身看作善事:“一种牺牲如果没有增进或不会增进幸福的总量,那么就是浪费。它唯一赞成的自我牺牲,是为了他人的幸福或有利于他人幸福的某些手段而做出的牺牲。”</p>
<hr>
<p>译者序 第 XIV 页<br>
穆勒关于功利主义的证明的思路大致是这样的:证明要么是根据原理的推理,要么是诉诸事实。功利主义的原理只能依靠诉诸事实,否则便无法证明。于是我们也只能用人类经验或者说是大多数人的看法,来证明人生应当追求的最终目的是“最大多数人的最大幸福”。问题在于如何用事实或大多数人的看法来证明“最大多数人的最大幸福”。穆勒的论证是:
能够证明一个对象可以看到的唯一证据,是人们实际上看见了它。能够证明一种声音可以听见的唯一证据,是人们听到了它;关于其他经验来源的证明,也是如此。与此类似,我以为,要证明任何东西值得欲求,唯一可能的证据是人们实际上欲求它。</p>
<hr>
<p>译者序 第 XVII 页<br>
总而言之,穆勒认为,正义是一种有别于仁慈和慷慨的底线道德,它的重要性在于通过禁止侵害他人的权利而满足人的安全需要。但由于没有统一的正义标准,故在不同的正义标准发生冲突时,取舍的标准唯有社会功利。由此看来,正义是建立在功利的基础上的。</p>
<hr>
<p>译者序 第 XXII 页<br>
总而言之,功利主义不承认个人具有神圣不可侵犯的自然权利,功利主义原则会导致为了多数人的利益侵害少数人的合法权益,一方面要求超出自然义务的“自我牺牲的”善行,另一方面给已经更幸运的人更大幸福而牺牲一部分人的福利和自由。</p>
<hr>
<p>译者序 第 XXII 页<br>
但传统功利主义的缺陷在于,它以效用的总和作为社会成就的判断准则,便导致了:(1)忽视基本权利等非效用因素;(2)以主观的心理感受来解释效用,忽视了与效用同样重要的主观能动方面(agency aspect);(3)忽视了分配公平。</p>
<hr>
<p>第 3 页<br>
伦理学中的直觉主义学派,与可称之为归纳主义的伦理学学派一样,坚持认为一般法则是必不可少的。这两个学派一致同意,个人行为是否合乎道德,不是一个直接知觉的问题,而是一个将法则运用于个别案例的问题。两个学派还在很大程度上认可同样的道德法则;但在道德法则得以成立的证据和权威依据方面,两派却有所分歧。在直觉主义学派看来,道德原则是先验自明的,只要理解了其词项的意义,就会立即为人同意。但在归纳主义学派看来,行为的对错与知识的真假一样,都要由观察和经验来判定。不过两派都同样认为,道德必定是根据原则推演出来的。直觉主义学派像归纳主义学派一样强烈地主张,道德科学是存在的,然而他们却很少做出努力,将这样一些先验的原则全部罗列出来,以便作为道德科学的前提;至于将这些不同的先验原则归约为个第一原理或道德义务的共同基础,他们所作的努力就更加少而又少了。他们要么认为,一些日常的道德准则具有先验的权威性,要么将某个更加不明显具有权威性、因而从未获得广泛接受的一般原则,说成是那些道德准则的共同基础。可是,为了支持他们的这些主张,就应当存在一个根本性的道德原则或法则,作为一切道德的根据,如果存在着几个不同的根本性道德原则或法则,那么在它们之间还应当有一种明确的优先排列次序;而且,那个唯一的根本性原则,或者当几个不同的根本性原则发生冲突时可以判定哪个原则应当优先加以考虑的规则,都应当是不证自明的。</p>
<hr>
<p>第 5 页<br>
终极目的的问题是无法直接证明的。任何事物凡能被证明是善的,必定是因为我们能够说明,它可以用作一种手段,使人获得某种无需证明就被认可为善的事物。医术有助于健康,所以被证明是好东西;但我们如何能够证明,健康是好呢?音乐特别能够带来快乐,所以是好东西;但我们又怎么能够证明,快乐是好事呢?因此,如果有人断言说,存在着一个全面的方案,它列出了所有本身为善的事物,而除此之外一切善的事物,则都不是作为目的的善而是作为手段的善存在的,那么,这个方案尽管可以被人接受也可以被人拒绝,却不是按通常的理解可以被证明的东西。不过我们并不想由此推断,接受或拒绝它必定依赖于盲目的冲动或任意的选择。证明这个词还有一种更广泛的意义,按照这种意义,这个问题就像其他任何一个有争议的哲学问题一样,也是可以证明的。证明的对象仍然属于理性官能的认识范围之内;不过理性官能处理这个问题并不是只有直觉的方法。我们可以提出各种考虑,这些考虑能够使理智赞成或者不赞成有关的学说,那也是一种证明。</p>
<hr>
<p>第 7 页<br>
主张功利理论的每一位著作家,从伊壁鸠鲁到边沁,都从来没有把功利理解为某种与快乐判然有别的东西,而是把它理解为快乐本身以及痛苦的解除;他们从来不把有用看作赏心悦目或带来美感的对立面,而总是宣称,有用尤其包着赏心悦目和带来美感的意思。</p>
<hr>
<p>第 8 页<br>
把“功利”或“最大幸福原理”当作道德基础的信条主张,行为的对错,与它们增进幸福或造成不幸的倾向成正比。所谓幸福,是指快乐和免除痛苦;所谓不幸,是指痛苦和丧失快乐。</p>
<hr>
<p>第 12 页<br>
做一个不满足的人胜于做一只满足的猪;做不满足的苏格拉底胜于做一个满足的傻瓜。如果那个傻瓜或猪有不同的看法,那是因为他们只知道自己那个方面的问题。而相比较的另一方即苏格拉底之类的人则对双方的问题都很了解。</p>
<hr>
<p>第 13 页<br>
享受高尚感情的能力,在大多数人的天性中都是一颗非常柔弱的花草,不仅很容易被各种不良的环境因素扼杀,而且只要缺乏营养,就很容易死亡;在大多年轻人中间,如果他们在生活中投身的职业和社会都不利于这种高级能力的不断运用,那么它就会迅速夭折。人们丧失自己的高等追求就像丧失自己理智上的趣味一样,都是因为他们没有时间或机会来沉浸其中;而他们之所以沉迷于低级快乐,不是因为他们有意偏好这些快乐,而是因为唯有这些快乐才是他们能够得到或者能够享受的东西。</p>
<hr>
<p>第 14 页<br>
根据上面所说明的“最大幸福原理”,人生的终极目的,就是尽可能多地免除痛苦,并且在数量和质量两个方面尽可能多地享有快乐,而其他一切值得欲求的事物(无论我们是从我们自己的善出发还是从他人的善出发),则都与这个终极目的有关,并且是为了这个终极目的的。</p>
<hr>
<p>第 20 页<br>
人们如果能够放弃自己个人的生活享受,由此对增进世上的幸福总量作出可贵的贡献,那么他们的确值得崇敬。但如果有人为了任何其他的目的放弃了自己的生活享受,或自称这样做了,那么他就像高踞于柱上的苦行僧,并不值得羡慕。他也许令人激动地证明了人能够做什么,但决不是值得人们仿效的榜样。
只有当世界的安排处于一种很不完善的状态时,绝对牺牲自己的幸福才会成为增进他人幸福的最好办法,可是既然这世界就是这样的不完善,所以我完全承认,准备作如此的牺牲是在人身上所能见到的最高美德。我还要补充说,在这样不完善的世界上,能够自觉地过没有幸福的日子,才最有希望得到能够得到的幸福,尽管这样说似乎有点自相矛盾。因为,唯有这种自觉才能使人感到,无论多么恶劣的命运,都无力将自己击倒,从而使自己能够超然于人生命运之上。人一旦有了这种感受之后,就不会过分地焦虑生活中的灾祸,并且能够像罗马帝国最黑暗时期中的许多斯多葛派信徒一样,在宁静中培养出能让自己满足的源泉,既不关心这种宁静带来的满足会持续多久,也不关心这种满足会不可避免地终结。</p>
<hr>
<p>第 20 页<br>
功利主义的道德承认,人具有一种力量,能够为了他人的福利而牺牲自己的最大福利。功利主义的道德只是不承认,牺牲本身就是善事。它认为,一种牺牲如果没有增进或不会增进幸福的总,那么就是浪费。它唯赞成的自我牺牲,是为了他人的幸福或有利于他人幸福的某些手段而做出的牺牲,这儿所说的他人,既可以全体人类,也可以是为人类集体利益所限定的个人。</p>
<hr>
<p>第 33 页<br>
无论道德义务是否还有除公众幸福之外的其他理由,人们总是欲求幸福的;无论人们自己的实践有多么不完善,他们总是欲求并赞扬别人做出在他们自己看来会增进自己幸福的事情。至于宗教性的动机,如果照大多数人所说,大家都相信上帝是善的,那么凡认为有利于公众幸福乃是善的本质或者哪怕仅仅是善的标准的人,就必然会相信,有利于公众幸福也是上帝所赞成的。因此外在的奖励和惩罚,无论是肉体的还是道义的,也不论是来自上帝还是来自我们的同胞,其全部力量,再加上人类天性能够容许的为上帝和同胞所做的一切无私奉献,便能够推动功利主义道德的实施,其推动的强度与功利主义道德得到承认的程度相一致;所以教育和大众教养的手段越多地被用于这个目的,这股推动力量就越强大。</p>
<hr>
<p>第 35 页<br>
与其他各种道德标准的约束力一样,功利主义道德标准的约束力也是人类出于良心的感情。无疑,这种约束力对于那些不具有出于良心的感情的人来说,由于无法诉诸这种感情,也就没有任何约束的作用;这些人既不会遵从功利主义道德原则,也不会因此而遵从其他任何道德原则。对于他们,任何道德都不起作用,除非通过外在的约束力。与此同时,出于良心的感情的确存在着,经验证明了,那是一个人性的事实,是实实在在的东西,能对受过良好教养的人产生巨大的作用。至今没有任何理由可以说,这种感情如果与功利主义相关联,就不能培养得像它与其他任何道德规则关联时那么强烈。</p>
<hr>
<p>第 38 页<br>
要和我们的同胞和谐一致的愿望,早已是人性中的一个有力原则,而且很幸运,它是无需我们不断进行灌输、而仅仅由于文明进展的影响就会变得更加强烈的社会感情之一。社会状态对于人来说一下子变得如此自然、如此必要、如此习惯,以致除非处在某些不寻常的环境之中或者由于要抽象思考,否则他决不会设想自己不是整体的一分子。随着人类进一步远离野蛮的孤立状态,这种关联也越来越牢固了。因此,当每个人设想自己命中注定要生活于其中的事态时,凡是构成一种社会状态的关键条件,都会日益成为他念念不忘的东西。所以,人与人组成的社会,除了主奴关系之外,要想不建立在照顾所有成员的利益的基础上,显然是不可能的。除非大家达成共识,所有成员的利益都应得到平等的考虑,否则不可能存在人人平等的社会。而既然在一切文明状态下,除了专制君主之外,每个人都会遇到身份地位平等的人,那么每个人都不得不与某些人平等相处。每一个时代都会取得某种进步,不断地向一种社会状态前进,使得人们不可能与任何一个人始终生活在不平等的关系之中。这样,人们在成年之后就无法设想,自己竟然可以完全不考虑他人的利益。他们必然会想,至少自己决不能去做严重有损于他人的事情,并且(哪怕只是为了保护自己)要生活在不断反对损害他人的社会之中。他们也知道如何与他人合作,懂得如何建议大家把集体利益而非个人利益作为行动的目标(至少是暂时)。当他们合作的时候,他们的个人目标与别人的目标是一致的;或至少会暂时地感到,别人的利益就是他们自己的利益。各种社会联系的加强和社会的健康发展,不仅会使每一个人更有兴趣在实际上顾及他人的福利,而且会使每一个人在感情上日益倾向于他人的福利,或者至少倾向于在更大的程度上实际考虑他人的福利。最后,他仿佛是本能地意识到,自己是一个当然要关心别人的人。对他来说,关注别人的福利就像关注自己平时的身体状况一样,已成为一件自然并且必然的事情。当一个人有了这样的感情,不论有多少,他都会出于最强烈的兴趣和同情心把这种感情展现出来,并且尽自己最大的力量来鼓励别人产生同样的感情;即便他本人丝毫没有这种感情,他也会像其他任何人一样,对别人应当产生这种感情具有很大的兴趣。结果,由于同情心的接触传染和教育的广泛影响,这种感情的最弱小的萌芽也会被人发掘出来予以精心培养;同时,由于各种外在约束力的强大作用,这种感情还获得了一张完备的围绕着自己的支持性关联网络。</p>
<hr>
<p>第 44 页<br>
幸福的成分十分繁多,每一种成分都是本身值得欲求的,而不仅仅是因为它能增加幸福的总量所以值得欲求。功利原则并不意味着,任何特定的快乐,如音乐;或者任何特定的痛苦免除,如健康,都应当视为达到某种叫做幸福的集合体的手段,并由此应当被人欲求。它们被人欲求并且值得欲求,乃在于它们自身。它们不仅是手段,也是目的的一部分。根据功利主义学说,美德原本不是目的的一部分,但它能够成为目的的一部分;它在那些无私地热爱它的人中间,已成了目的的一部分,并且不是作为达到幸福的一种手段,而是作为他们幸福的组成部分,被欲求并被珍惜。</p>
<hr>
<p>第 46 页<br>
人们无论欲求什么东西,如果不是把它当作达到自身之外的某个目的、从而最终达到幸福的手段,那么就是把它自身当作了幸福的一部分,而且除非它已成了幸福的一部分,否则就不会因为自身而被人欲求。那些为了美德本身而欲求美德的人,或者是因为,对美德的感受便是一种快乐,或者是因为,对没有美德的感受则是一种痛苦,或者是因为两者兼而有之。事实上,快乐和痛苦几乎不可分离,而总是结伴而行的,一个人若因具备某种程度的美德感到快乐,那么他就会因不具备更多的美德而感到痛苦。如果这种美德不能使他感到快乐,那种美德不能使他感到痛苦,那么他就不会爱好或欲求美德了,或者,他会仅仅因为美德能给他或他所关心的人带来其他的福利而欲求美德。</p>
<hr>
<p>第 60 页<br>
无论是何种形式的义务,义务这一概念总是包含着,我们可以正当地强迫一个人去履行它。义务这种东西是可以强行索要的,就像债务可以强行索要一样。任何事情,除非我们认为可以强制他履行,否则就不能称为他的义务。出于审慎,或者为了其他人的利益,可以让我们不再强制他履行义务;但是大家都很清楚,具有义务的人本人是没有权利对强制履行进行抱怨的。相反,另有些事情,我们也希望人们去做,如果他们做了,我们也会喜欢或者称赞他们,如果他们不做,我们也许不喜欢或者瞧不起他们。但我们还是会承认,这些事情不是他们非做不可的,它们不属于道德义务,我们不能因为这些事情谴责他们,也就是说,我们不认为他们应当为这些事情而受到惩罚。我们是怎么得到这些应该受罚和不该受罚的观念的,也许看了下文就会明白;但我认为,这种区分无疑构成了行为对错概念的基础。如果我们认为,一个人应当为某个行为受到惩罚,那么就会说这个行为是错的,但如果我们认为,一个人不应当为了这个行为而受到惩罚,那么就不会说它是错的,而会用其他一些表示不喜欢或者贬抑的语词来描述这个行为。如果我们愿意看到一个人受到强制去做某件事,那么就会说这样做是对的,但如果我们只愿看到一个人受到劝说和鼓励去做这件事,那么就不会说这样做是对的,而仅仅会说它是值得欲求的或值得称赞的。</p>
<hr>
<p>第 65 页<br>
有人会说,当我们觉得自己的正义感受到触犯时,我们并没有想到整个社会或任何集体利益,我们想到的只是具体的事情。但这并不能构成对上述学说的反驳。仅仅因为遭受痛苦,就感到愤怒,这当然很常见,可是不值得称赞。一个人的愤怒如果的确是一种道德感情,那么他首先会考虑一个行为是否该受责备,然后才会决定是否要对它感到愤怒,这样一个人也许不会明确地对自己说,自己是在代表社会的利益,但他毫无疑问会感到,自己是在坚持一条行为规则,亦即不仅要考虑自己的利益同时也要考虑别人的利益。如果他没有感到这一点,也就是说他只考虑那个行为对他个人有什么影响,那么,他就没有正义的意识,他并不关心自己的行为是否正义。这一点甚至也得到了反功利主义的伦理学家的承认。当康德(如前面提到过的那样)提出“你的行为,要让它所根据的行为规则可以被所有的理性人接纳为一条法则”,把它作为基本的道德原则时,他实质上承认,当行为者凭良心判定自己的行为是否合乎道德时,心中想到的必定是人类的集体利益,或至少是不加区别的人类利益。否则他的话就没有意义,因为我们甚至不能有道理地坚持认为,一种极端利己的行为规则是不可能被所有的理性人采纳的-事物的本性中就存在着不可逾越的障碍,使这种行为规则无法为人采纳。康德提出的原则要有意义,就必定含有这样的意思:我们的行为应当遵守的规则,是所有的理性人都会采纳的有益于他们集体利益的行为规则。</p>
<hr>
<p>第 65 页<br>
总而言之,正义这个观念含有两种要素,一是行为规则,二是赞同行为规则的情感。第一个要素必定被认为是全人类共有的,而且必定是为了全人类的利益。另一个要素(情感)则是一种欲望,想要违反行为规则的人受到惩罚。此外,正义的观念还含有一种想法,即认为某个确定的人因他人的违规行为而受到损害,(用适合于这种情况的表达式来说)他的权利因而受到侵害。而在我看来,正义的情感原本是一种动物性的报复欲望,因一个人本人或他所同情的对象受到伤害或损害而欲求反击或报复,但后来由于人的博大的同情能力和明智的自我利益概念的作用,这种报复的欲望把自己的同情对象扩展到了所有的人。正义的情感所具有的道德性,便来自于它的后几个要素,而它特有的感人性和自我肯定的力量,则来自它此前的原始报复欲望。</p>
<hr>
<p>以上摘自:<br>
<img src="https://s2.loli.net/2022/08/11/pQlfVLRrUNvKna6.jpg" alt="《功利主义》"><br>
<a href="https://book.douban.com/subject/25908107/">《功利主义》</a><br>
作者: [英] 约翰·穆勒<br>
出版社: 商务印书馆<br>
译者: 徐大建<br>
ISBN: 9787100099417</p>
年度播客单集推荐(2021)
https://acuario.xyz/others/podcast-recommendation-2021/
2023-09-27T18:25:39+00:00
2021-12-19T15:20:22+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>从 2016 年接触播客至今已经快 6 个年头,毫无疑问我从播客这个媒介中汲取了太多养分。看着 Pocket Casts 里日积月累的收听记录,想到可以每年做一次个人年度播客推荐。一方面可以让自己回顾一整年播客内容消费的心路历程,更重要的是为各位刚接触播客 / 播客重度听众推荐一些制作精良、题材新颖广泛的节目单集。</p>
<p>节目排名不分先后,分类粒度也比较粗,各位可以按话题分类或单集简介挑选收听。本页快速播放控件均由 listennote 提供(除非节目未被 listennote 收录),如不能播放或打开,请使用正确的上网方式进行访问。</p>
<p>你也可以直接访问我在 listennote 建立的播放列表:<a href="https://lnns.co/VRUBZq_ceXa">「年度播客单集推荐-2021」</a></p>……
<p>从 2016 年接触播客至今已经快 6 个年头,毫无疑问我从播客这个媒介中汲取了太多养分。看着 Pocket Casts 里日积月累的收听记录,想到可以每年做一次个人年度播客推荐。一方面可以让自己回顾一整年播客内容消费的心路历程,更重要的是为各位刚接触播客 / 播客重度听众推荐一些制作精良、题材新颖广泛的节目单集。</p>
<p>节目排名不分先后,分类粒度也比较粗,各位可以按话题分类或单集简介挑选收听。本页快速播放控件均由 listennote 提供(除非节目未被 listennote 收录),如不能播放或打开,请使用正确的上网方式进行访问。</p>
<p>你也可以直接访问我在 listennote 建立的播放列表:<a href="https://lnns.co/VRUBZq_ceXa">「年度播客单集推荐-2021」</a></p>
<h2 id="社会">社会</h2>
<h3 id="当我们谈论自由主义的时候我们在谈论什么---不合时宜">当我们谈论自由主义的时候,我们在谈论什么? - 不合时宜</h3>
<ul>
<li><a href="https://justpodmedia.com/shows/theweirdo/TheWeirdo-ep56-20210109?key=788">🔗节目页面</a></li>
<li><a href="https://justpodmedia.com/shows/theweirdo/episodes">🔗节目官网</a></li>
</ul>
<blockquote>
<p>尽管自由主义是一个如此高频出现的概念,但要说清它的内涵却并非易事。自由主义到底是什么?经历了怎样的变迁?又如何形塑了我们当今的世界?</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/不合时宜/当我们谈论自由主义的时候我们在谈论什么-7_kgrCPuHO1/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="反思过劳时代里工作的意义---不合时宜">反思过劳时代里,「工作」的意义 - 不合时宜</h3>
<ul>
<li><a href="https://justpodmedia.com/shows/theweirdo/TheWeirdo-ep58-20210123?key=811">🔗节目页面</a></li>
<li><a href="https://justpodmedia.com/shows/theweirdo/episodes">🔗节目官网</a></li>
</ul>
<blockquote>
<p>这期节目邀请了「反 996 软件授权协议」的发起人 Suji Yan,以及零工经济领域的研究者阿克加,一起聊了聊过劳时代下人们的处境以及解决之道。前者是一位技术从业者,而后者更具社科视角,他们从不同领域出发补充了对 996 这个话题的思考维度。最后嘉宾们也探讨了「工作的意义」,聊了聊闲暇的重要性。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/不合时宜/反思过劳时代里工作的意义-9HAQfn0xFM8/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="什么是自律读书和他律读书---梁文道八分">什么是"自律读书"和"他律读书"? - 梁文道·八分</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=406394">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=11">🔗节目官网</a></li>
</ul>
<blockquote>
<p>1、为什么不喜欢开书单?<br>
2、读书应该快读还是慢读?<br>
3、书读完就忘了,怎么办?<br>
4、什么是他律读书和自律读书?</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/梁文道八分/278-什么是自律读书和他律读书-E1fa2tDwluB/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="新垣结衣结婚艺人为什么会成为国民老婆---梁文道八分">新垣结衣结婚:艺人为什么会成为"国民老婆"? - 梁文道·八分</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=417644">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=11">🔗节目官网</a></li>
</ul>
<blockquote>
<p>1、新垣结衣星野源结婚,为什么被关注? <br>
2、什么样的艺人,会被叫“老婆”或者“老公”?<br>
3、亲密关系和 Baby talk 的关系。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/梁文道八分/286-新垣结衣结婚艺人为什么会成为国民老婆-gXCfyxvFW7K/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="什么叫作求仁得仁---梁文道八分">什么叫作"求仁得仁"? - 梁文道·八分</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=435394">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=11">🔗节目官网</a></li>
</ul>
<blockquote>
<p>1、复旦杀人案,为什么不应该说“活该”?<br>
2、什么叫作“求仁得仁”?<br>
3、为什么“名正言顺”很重要?<br>
4、杀、弑和诛有什么分别?</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/梁文道八分/296-什么叫作求仁得仁-5qUHyuZwesc/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="杀人犯欧金中为什么那么多人希望他活着---404档案馆">杀人犯欧金中,为什么那么多人希望他活着? - 404档案馆</h3>
<ul>
<li><a href="https://chinadigitaltimes.net/chinese/672262.html">🔗节目页面</a></li>
<li><a href="https://chinadigitaltimes.net/chinese/category/cdt-stories/%e2%9e%bd404%e6%a1%a3%e6%a1%88%e9%a6%86">🔗节目官网</a></li>
</ul>
<blockquote>
<p>「张献忠」成为敏感词</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/404档案馆/第33期杀人犯欧金中为什么那么多人希望他活着-z6vZMqLOAhc/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="在资本主义文化中生活的少数派---翻转电台flipradio">在资本主义文化中生活的少数派 - 翻转电台FlipRadio</h3>
<ul>
<li><a href="https://anchor.fm/flipradio/episodes/31-eau211">🔗节目页面</a></li>
</ul>
<blockquote>
<p>• 什么是资本主义文化<br>
• 碎片化、技术性、无自我、不断更新、矛盾的、异化的<br>
• 资本主义文化的实体<br>
• 如何抵抗这种文化</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/翻转电台flipradiovpn/翻电问答-31-在资本主义文化中生活的少数派-3ltiCPgNJyT/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="文艺青年概念回眸一个逝去的好日子---翻转电台flipradio">“文艺青年”概念回眸:一个逝去的好日子 - 翻转电台FlipRadio</h3>
<ul>
<li><a href="https://anchor.fm/flipradio/episodes/58-e15f4u6">🔗节目页面</a></li>
</ul>
<blockquote>
<p>“文艺青年”概念的提出,贬义化,和彻底的消失,这个概念的变迁,也是从1990年到现在30年社会变迁的缩影,这是一个值得去探索的概念。<br>
• 不要小瞧这个词汇<br>
• 文艺青年的发源:两个条件的融合<br>
• 文艺青年的落败:一种生活形式的剧变<br>
• 不再有文艺青年:一个紧迫的社会<br>
• 一种好日子</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/翻转电台flipradiovpn/翻电问答-58-文艺青年概念回眸一个逝去的好日子-cNWGH0zP1gD/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h2 id="科技">科技</h2>
<h3 id="哥吉拉大戰摩斯拉--科技業的雙頭壟斷---科技島讀">哥吉拉大戰摩斯拉 — 科技業的雙頭壟斷 - 科技島讀</h3>
<ul>
<li><a href="https://daodu.tech/03-15-2021-godzilla-fights-mothra-tech-duopoly">🔗节目页面</a></li>
<li><a href="https://daodu.tech/">🔗节目官网</a></li>
</ul>
<blockquote>
<p>企業的終極夢想是寡佔,但更常見的狀態是雙頭壟斷(duopoly)。雙頭壟斷是市場由兩大企業瓜分,並遙遙領先剩下的競爭者,就像怪獸哥吉拉(Godzilla)與摩斯拉大戰。科技業的雙頭壟斷有 iOS 與 Android、數位廣告的 Google 與臉書,或是晶圓代工的台積電與三星。<br>
雙頭對決雖然壯觀,但也值得探究雙頭壟斷是如何造成的?是否穩定?以及科技業的雙頭壟斷與其他產業有何不同?</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/科技島讀/ep136-哥吉拉大戰摩斯拉-科技業的雙頭壟斷-EFwPtqQlRzj/embed/" height="180px" width="100%" style="width: 1px; min-width: 100%;" frameborder="0" scrolling="no" loading="lazy"></iframe>
<h3 id="作为先知的中本聪这个时代名为密码朋克---忽左忽右">作为先知的中本聪:这个时代名为密码朋克 - 忽左忽右</h3>
<ul>
<li><a href="https://justpodmedia.com/shows/left-right/leftright-ep89-20200601?key=279">🔗节目页面</a></li>
<li><a href="https://justpodmedia.com/shows/left-right">🔗节目官网</a></li>
</ul>
<blockquote>
<p>关于比特币之父中本聪的前世今生和一些科技八卦</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/忽左忽右/89-作为先知的中本聪这个时代名为密码朋克-SMpcBwKHt94/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="李如一对互联网的幻灭以及一些理想主义的对抗---声东击西">李如一:对互联网的幻灭,以及一些理想主义的对抗 - 声东击西</h3>
<ul>
<li><a href="https://etw.fm/189">🔗节目页面</a></li>
<li><a href="https://etw.fm/">🔗节目官网</a></li>
</ul>
<blockquote>
<p>因为对互联网感到「幻灭」,所以选择与互联网保持距离,重新发现「实体物」的意义。但,依然很喜欢互联网,并且还在不断体验各种新鲜好玩的 APP。<br>
节目对谈的关键词之一是「五年来的变化」,但也谈到了过去几十年来依然保持了原样的那些事物,比如尼尔·波兹曼的寓言以及人人都知道的「娱乐至死」;又比如电子书和音乐软件,至今未能取代实体书和唱片机。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/声东击西/189-李如一对互联网的幻灭以及一些理想主义的对抗-im7_VB20ban/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h2 id="电影">电影</h2>
<h3 id="好萊塢殺人事件曼森家族---lights-out-熄燈之後">好萊塢殺人事件|曼森家族 - Lights Out 熄燈之後</h3>
<ul>
<li><a href="https://player.soundon.fm/p/f5cd3763-0c1f-46f5-8169-f86e470e0e17/episodes/af9d47a9-e8b9-431d-b2f4-4ac2bad8e35d">🔗节目页面(上)</a></li>
<li><a href="https://player.soundon.fm/p/f5cd3763-0c1f-46f5-8169-f86e470e0e17/episodes/fd2c47d8-e50a-4f54-a75d-d74e0d156685">🔗节目页面(下)</a></li>
<li><a href="http://linktr.ee/lightsoutpodcast">🔗节目官网</a></li>
</ul>
<blockquote>
<p>这两集节目讲述了震惊全美的好莱坞谋杀案。配合电影《好莱坞往事》食用更佳。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/lights-out-熄燈之後/s2-ep06-好萊塢殺人事件曼森家族上-ftZ9zi30O2p/embed/" height="180px" width="100%" style="width: 1px; min-width: 100%;" frameborder="0" scrolling="no" loading="lazy"></iframe>
<iframe src="https://www.listennotes.com/podcasts/lights-out-熄燈之後/s2-ep07-好萊塢殺人事件曼森家族下-et2A5IZ8iYM/embed/" height="180px" width="100%" style="width: 1px; min-width: 100%;" frameborder="0" scrolling="no" loading="lazy"></iframe>
<h2 id="文学艺术">文学&艺术</h2>
<h3 id="葛宇路没皮没脸待着也挺好---艺术折叠">葛宇路:没皮没脸待着也挺好 - 艺术折叠</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=427744">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=213">🔗节目官网</a></li>
</ul>
<blockquote>
<p>有人说,当代艺术是反对阐释的艺术,当你想要去解读当代艺术作品的时候,就已经不是那个作品本身想要表达的意思了——这是我对当代艺术最肤浅的了解。当年的葛宇路事件应该不必再赘述,这期节目邀请到了葛宇路事件的主角葛宇路来聊了当代艺术的一些话题,算是比较有趣的一期节目。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/艺术折叠-当代艺术解密之旅/葛宇路没皮没脸待着也挺好-Z1FaWbq3y26/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="王瑞芸躲开人群寻找自在杜尚不想当艺术家---艺术折叠">王瑞芸:躲开人群,寻找自在,杜尚不想当艺术家 - 艺术折叠</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=450194">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=213">🔗节目官网</a></li>
</ul>
<blockquote>
<p>1、杜尚为什么在当代艺术里非常重要? <br>
2、怎么理解杜尚的最后一件作品? <br>
3、现在的艺术家,有在滥用杜尚的观念吗? <br>
4、如何成为一名生活艺术家?</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/艺术折叠-当代艺术解密之旅/王瑞芸躲开人群寻找自在杜尚不想当艺术家-0hL-4Z2rK_q/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="许子东--天真你会相信文字给的希望吗---理想青年">许子东 × 天真:你会相信文字给的希望吗? - 理想青年</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=432294">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=215">🔗节目官网</a></li>
</ul>
<iframe src="https://www.listennotes.com/podcasts/理想青年/04-许子东-天真你会相信文字给的希望吗-K2wmXo5f3Hr/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h2 id="生活">生活</h2>
<h3 id="三个非典型直男的生活漫谈---看理想电台">三个非典型直男的生活漫谈 - 看理想电台</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=435044">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=13">🔗节目官网</a></li>
</ul>
<blockquote>
<p>看理想 是笔者本人很喜欢的一个内容平台,这期节目是看理想编辑部三个直男同事的闲聊,他们分享了一些节目制作背后的故事,也聊到了在一家女性人数占绝对优势的公司工作是一种怎样的体验,以及身边这些优秀的女生对其有怎样的影响,并从她们身上学到了什么。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/看理想电台/203-三个非典型直男的生活漫谈-PEkoQy0Flib/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="人生若无悔那该多无趣呀---看理想电台">"人生若无悔,那该多无趣呀" - 看理想电台</h3>
<ul>
<li><a href="https://shop.vistopia.com.cn/article?article_id=451244">🔗节目页面</a></li>
<li><a href="https://shop.vistopia.com.cn/detail?id=13">🔗节目官网</a></li>
</ul>
<blockquote>
<p>看理想编辑部再网上征集了一些从错误的选择或失败中走出来的故事。
故事中,有人觉得在不合适的岗位工作是错误的,所以决定遵从内心,辞职追梦;也有人追梦失败了,又反省自己,回到曾经的行业,追求稳定的生活。
这期节目是大家的投稿放送,可以感受一个又一个真实又鲜活的灵魂。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/看理想电台/208-人生若无悔那该多无趣呀-TP3Jnj2VALw/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="超前消费和延迟满足你怎么选---andrewguan">超前消费和延迟满足你怎么选 - AndrewGuan</h3>
<ul>
<li><a href="https://www.xiaoyuzhoufm.com/episode/608c88a5925f506c9b31daca">🔗节目页面</a></li>
<li><a href="https://www.xiaoyuzhoufm.com/podcast/6082a6e13eca5e0bc0ff97d1">🔗节目官网</a></li>
</ul>
<blockquote>
<p>这是笔者非常喜欢的一期日常单口闲话节目,在对抗消费主义的今天,隔三差五把这期节目翻出来,一定会常听常新。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/andrewguan/004-超前消费和延迟满足你怎么选-IBETrXxb5Dt/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="自己的东西自己珍惜自己的回忆要留在自己的硬盘里吗---andrewguan">自己的东西自己珍惜,自己的回忆要留在自己的硬盘里,吗? - AndrewGuan</h3>
<ul>
<li><a href="https://www.xiaoyuzhoufm.com/episode/60d2f5cf9e282ee17815b646">🔗节目页面</a></li>
<li><a href="https://www.xiaoyuzhoufm.com/podcast/6082a6e13eca5e0bc0ff97d1">🔗节目官网</a></li>
</ul>
<blockquote>
<p>生活在互联网时代的我们,如何和自己的数据、数字遗产达成和解?节目没有给出什么答案,但或许能让你多一种看待自身和数据关系的视角。</p>
</blockquote>
<iframe src="https://www.listennotes.com/podcasts/andrewguan/016-自己的东西自己珍惜自己的回忆要留在自己的硬盘里吗-nw1Q_8IRWDV/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="我好像找到自己看书记不住的原因了树林里的陌生人---andrewguan">我好像找到自己看书记不住的原因了《树林里的陌生人》 - AndrewGuan</h3>
<blockquote>
<p>主播从一本书讲起,看似是分享读后感,但给人的感受已经超越了书本和节目本身。</p>
</blockquote>
<ul>
<li><a href="https://www.xiaoyuzhoufm.com/episode/60dc93bb79023a50e603875f">🔗节目页面</a></li>
<li><a href="https://www.xiaoyuzhoufm.com/podcast/6082a6e13eca5e0bc0ff97d1">🔗节目官网</a></li>
</ul>
<iframe src="https://www.listennotes.com/podcasts/andrewguan/017-我好像找到自己看书记不住的原因了树林里的陌生人--UYLy5MVl7f/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="我的-iphone-13-mini-是怎么用的---andrewguan">我的 iPhone 13 mini 是怎么用的 - AndrewGuan</h3>
<ul>
<li><a href="https://www.xiaoyuzhoufm.com/episode/616ac986d8fa23fb00fc4d86">🔗节目页面</a></li>
<li><a href="https://www.xiaoyuzhoufm.com/podcast/6082a6e13eca5e0bc0ff97d1">🔗节目官网</a></li>
</ul>
<iframe src="https://www.listennotes.com/podcasts/andrewguan/027-我的-iphone-13-mini-是怎么用的-mCvriN_ojaq/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
<h3 id="闲话大理---执异">闲话大理 - 执异</h3>
<ul>
<li><a href="https://zhiyi.life/episodes/3">🔗节目页面</a></li>
<li><a href="https://zhiyi.life/">🔗节目官网</a></li>
</ul>
<iframe src="https://www.listennotes.com/podcasts/执异/执异-ep-03-闲话大理-4pR9ozlDqdW/embed/" height="170px" width="100%" style="width: 1px; min-width: 100%;" loading="lazy" frameborder="0" scrolling="no"></iframe>
PHP数组取交集的方法对比及性能测试
https://acuario.xyz/posts/php-intersect-performance/
2023-09-27T18:25:39+00:00
2021-09-11T12:05:20+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>PHP 作为世界上最好的语言,怎么可能有不完美的地方呢?最近因为业务上的一个需求,遇到了一个求几个大数组交集的场景。在实现的过程中,毫不意外地遭遇了性能问题。这里记录一下关于 PHP 取数组交集的性能优化思考。</p>
<p>不想看过程的可以直接跳到文末看结论。</p>……
<p>PHP 作为世界上最好的语言,怎么可能有不完美的地方呢?最近因为业务上的一个需求,遇到了一个求几个大数组交集的场景。在实现的过程中,毫不意外地遭遇了性能问题。这里记录一下关于 PHP 取数组交集的性能优化思考。</p>
<p>不想看过程的可以直接跳到文末看结论。</p>
<h2 id="场景描述">场景描述</h2>
<ol>
<li>接口输出一个简单的 list 接口,大概 100+ 行数据,每行数据有 4 个字段都需要进行交集操作。即该接口总共需要进行 400-500 次交集操作。</li>
<li>进行交集操作的成员数组数据量大概在 2w 左右,全部为数值(类型不敏感,可根据需要转换为 string / int 类型)</li>
<li>可以使用 redis 作为缓存。</li>
</ol>
<p>伪代码如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">Class</span> <span class="nc">List</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">list</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mf">3.</span><span class="o">..</span><span class="p">];</span> <span class="c1">// count($arr1) = 20000
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nv">$arr2</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mf">5.</span><span class="o">..</span><span class="p">];</span> <span class="c1">// count($arr2) = 20000
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">foreach</span> <span class="p">(</span><span class="nv">$list</span> <span class="k">as</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$list</span><span class="p">[</span><span class="s1">'key1'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nx">arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$list</span><span class="p">[</span><span class="s1">'key2'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nx">arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$list</span><span class="p">[</span><span class="s1">'key3'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nx">arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$list</span><span class="p">[</span><span class="s1">'key4'</span><span class="p">]</span> <span class="o">=</span> <span class="nx">intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nx">arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$list</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="实现路径">实现路径</h2>
<h3 id="php-原生方法">PHP 原生方法</h3>
<p>众所周知 PHP 自带了一大堆数组的助手方法可以直接调用,实在是太方便不过了,直接一把梭搞定:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">array_intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nv">$arr2</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>如果这个方法这么好用,我当然也就不用大费周章写这篇文章了。实现归实现,在满足场景需求的情况下,整个接口的响应速度来到了惊人的 30+s。可以说是非常棒了,可以直接气死产品和甲方。</p>
<h3 id="redis-集合求交集">Redis 集合求交集</h3>
<p>既然可以使用 redis,那我直接用 redis 的 set 来搞交集不就行了。这里写的是 Yii 2.0 框架调用 redis 的方法,其他框架大同小异这里就不赘述了(这年头不会有人不用框架开发吧?):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sadd</span><span class="p">(</span><span class="s1">'redisarr1'</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr1</span><span class="p">);</span> <span class="c1">// 设置集合arr1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sadd</span><span class="p">(</span><span class="s1">'redisarr1'</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr2</span><span class="p">);</span> <span class="c1">// 设置集合arr1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sinter</span><span class="p">(</span><span class="s1">'redisarr1'</span><span class="p">,</span> <span class="s1">'redisarr2'</span><span class="p">);</span> <span class="c1">// 求两个集合的交集
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>该方法也挺简单,经测试性能有所提升。</p>
<h3 id="php-优化方法">PHP 优化方法</h3>
<h4 id="类型转换">类型转换</h4>
<p>不知道 PHP 的取交集方法 array_intersect() 是否对数组元素的类型存在影响,猜测如果使用整型作为键值的话是不是会更快一些,那么在取交集前可以先进行类型转换。</p>
<h4 id="数组反转">数组反转</h4>
<p>对于 PHPer 来说,判断某一元素是否在数组中出现,通常会使用 in_array() 方法进行判断。数组较小时,性能问题可以忽略不计。但在遭遇大数组时,则可能回产生糟糕的性能问题。解决这个问题的通行做法是先使用 array_flip() 将数组的 key-value 进行反转,然后再使用 isset() 方法进行判断。</p>
<p>从这个思路出发,我琢磨着是不是取交集也可以使用类似的方法进行处理,直接对数组键名而不是键值进行取交集操作。反正也就是先反转一下数组而已:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">array_intersect</span><span class="p">(</span><span class="o">...</span><span class="nv">$arrays</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$flip_arrays</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"> <span class="k">foreach</span> <span class="p">(</span><span class="nv">$arrays</span> <span class="k">as</span> <span class="nv">$arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$flip_arrays</span><span class="p">[]</span> <span class="o">=</span> <span class="nx">array_flip</span><span class="p">(</span><span class="nv">$arr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nv">$result</span> <span class="o">=</span> <span class="nx">array_intersect_key</span><span class="p">(</span><span class="o">...</span><span class="nv">$flip_arrays</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">array_flip</span><span class="p">(</span><span class="nv">$result</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="性能测试">性能测试</h2>
<h3 id="测试原理">测试原理</h3>
<p>测试中直接生成大小为 100w 的随机数字数组。分别测试四种取交集方法:</p>
<ol>
<li>PHP 原生方法 array_intersect() 对整型数组取交集</li>
<li>PHP 原生方法 array_intersect() 对字符串数组取交集</li>
<li>先 array_flip() 反转数组的 key-value,再对反转后的数组键名使用 array_intersect_key() 取交集</li>
<li>edis 的 set 取交集</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">Class</span> <span class="nc">IntersectTest</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="nv">$time</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">actionTest</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$n</span> <span class="o">=</span> <span class="mi">1000000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr1</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr2</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="nv">$i</span> <span class="o"><=</span> <span class="nv">$n</span><span class="p">;</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$number</span> <span class="o">=</span> <span class="nx">rand</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">30000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr1</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr2</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr3</span><span class="p">[]</span> <span class="o">=</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span><span class="nv">$number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$arr4</span><span class="p">[]</span> <span class="o">=</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span><span class="nv">$number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sadd</span><span class="p">(</span><span class="s1">'redisIntarr1'</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sadd</span><span class="p">(</span><span class="s1">'redisIntarr2'</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sadd</span><span class="p">(</span><span class="s1">'redisStringarr1'</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sadd</span><span class="p">(</span><span class="s1">'redisStringarr2'</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">print_r</span><span class="p">(</span><span class="s1">'PHP version: '</span> <span class="o">.</span> <span class="nx">phpversion</span><span class="p">()</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">print_r</span><span class="p">(</span><span class="s1">'Tets sample count: '</span> <span class="o">.</span> <span class="nv">$n</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'Test begin'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ret1</span> <span class="o">=</span> <span class="nx">array_intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nv">$arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'PHP int array_intersect'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ret2</span> <span class="o">=</span> <span class="nx">array_intersect</span><span class="p">(</span><span class="nv">$arr3</span><span class="p">,</span> <span class="nv">$arr4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'PHP string array_intersect'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ret3</span> <span class="o">=</span> <span class="nx">self</span><span class="o">::</span><span class="na">array_intersect</span><span class="p">(</span><span class="nv">$arr1</span><span class="p">,</span> <span class="nv">$arr2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'PHP int array_flip & array_intersect'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ret4</span> <span class="o">=</span> <span class="nx">self</span><span class="o">::</span><span class="na">array_intersect</span><span class="p">(</span><span class="nv">$arr3</span><span class="p">,</span> <span class="nv">$arr4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'PHP string array_flip & array_intersect'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ret5</span> <span class="o">=</span> <span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sinter</span><span class="p">(</span><span class="s1">'redisIntarr1'</span><span class="p">,</span> <span class="s1">'redisIntarr2'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'redis int array_intersect'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ret6</span> <span class="o">=</span> <span class="nx">Yii</span><span class="o">::</span><span class="nv">$app</span><span class="o">-></span><span class="na">redis_connection</span><span class="o">-></span><span class="na">sinter</span><span class="p">(</span><span class="s1">'redisStringarr1'</span><span class="p">,</span> <span class="s1">'redisStringarr2'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="na">infoTime</span><span class="p">(</span><span class="s1">'redis string array_intersect'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * 魔改的数组取交集方法
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @param ...$arrays
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @return int[]|string[]
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">array_intersect</span><span class="p">(</span><span class="o">...</span><span class="nv">$arrays</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$flip_arrays</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"> <span class="k">foreach</span> <span class="p">(</span><span class="nv">$arrays</span> <span class="k">as</span> <span class="nv">$arr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$flip_arrays</span><span class="p">[]</span> <span class="o">=</span> <span class="nx">array_flip</span><span class="p">(</span><span class="nv">$arr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nv">$result</span> <span class="o">=</span> <span class="nx">array_intersect_key</span><span class="p">(</span><span class="o">...</span><span class="nv">$flip_arrays</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">array_flip</span><span class="p">(</span><span class="nv">$result</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">infoTime</span><span class="p">(</span><span class="nv">$info</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">self</span><span class="o">::</span><span class="nv">$time</span> <span class="o">===</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="nv">$time</span> <span class="o">=</span> <span class="nx">microtime</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">print_r</span><span class="p">(</span><span class="s1">'exeTime='</span> <span class="o">.</span> <span class="nx">self</span><span class="o">::</span><span class="na">getExecuteTime</span><span class="p">()</span> <span class="o">.</span><span class="s1">' '</span> <span class="o">.</span> <span class="nv">$info</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">getExecuteTime</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$now</span> <span class="o">=</span> <span class="nx">microtime</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">self</span><span class="o">::</span><span class="nv">$time</span> <span class="o">===</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="nv">$time</span> <span class="o">=</span> <span class="nv">$now</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nv">$executeTime</span> <span class="o">=</span> <span class="nv">$now</span> <span class="o">-</span> <span class="nx">self</span><span class="o">::</span><span class="nv">$time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nx">self</span><span class="o">::</span><span class="nv">$time</span> <span class="o">=</span> <span class="nv">$now</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">round</span><span class="p">(</span><span class="nv">$executeTime</span><span class="p">,</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="测试结果">测试结果</h3>
<pre tabindex="0"><code>PHP version: 7.3.6
Tets sample count: 20000
exeTime=0 Test begin
exeTime=0.043 PHP int array_intersect
exeTime=0.019 PHP string array_intersect
exeTime=0.002 PHP int array_flip & array_intersect
exeTime=0.002 PHP string array_flip & array_intersect
exeTime=0.118 redis int array_intersect
exeTime=0.117 redis string array_intersect
PHP version: 7.3.6
Tets sample count: 1000000
exeTime=0 Test begin
exeTime=2.874 PHP int array_intersect
exeTime=2.164 PHP string array_intersect
exeTime=0.038 PHP int array_flip & array_intersect
exeTime=0.077 PHP string array_flip & array_intersect
exeTime=0.119 redis int array_intersect
exeTime=0.119 redis string array_intersect
</code></pre><ul>
<li>从上述测试结果来看,如果按文首所述的场景,直接使用原生方法进行实现的接口响应耗时 <code>17-21s (单次交集操作 0.043s)</code>。<br>
使用魔改方法优化后的接口响应耗时 <code>0.8-1s (单次交集操作 0.002s)</code></li>
<li>如果数组大小为 100w 级,那么性能问题将会被放大,差异大概是两个数量级的样子,也难怪 PHP 是世界上最好的语言。</li>
<li>从测试结果来看 redis 的集合取交集性能表现也还是不错的,普通的 web 场景足够应付。吊诡的是不同数量级大小的数组居然对其性能没有影响,这里猜测这个耗时可能主要被建立 redis 连接的过程给占用了。</li>
</ul>
<h2 id="结论">结论</h2>
<ol>
<li>PHP 自带的 <code>array_intersect()</code> 方法只适合交集数组长度比较小的场景(看起来最好控制在 1k 以内),否则性能爆炸烂</li>
<li>如果需要对大数组进行交集操作,可以考虑使用魔改的 <code>array_intersect()</code> 方法,先 <code>array_flip()</code> 反转数组的键值,然后使用 <code>array_intersect_key()</code> 去交集,这样会快至少三个数量级。</li>
<li>不同数据类型的元素确实会对 PHP 原生方法的数组取交集性能产生影响,字符串类型的元素取交集性能更好。</li>
<li>redis 的交集操作也挺好用,在上述方法不可使用的情况下,可以考虑使用 redis 进行交集操作。</li>
</ol>
<h2 id="后话">后话</h2>
<p>这个优化过程其实带出了几个值得思考的问题:</p>
<ol>
<li>为什么 PHP 判断元素存在时,使用键名判断比使用键值判断性能更好?</li>
<li>PHP 数组取交集的性能问题是否也是因为上述原因导致?</li>
<li>为什么使用 PHP 原生方法取交集时,数组元素为字符串型 比 数组元素为整型 的性能更好?</li>
<li>redis 的取交集操作性能可以有多好?百万级大小的数组在 redis 取交集时,实际性能如何?
这些问题就暂时不在这篇水文内展开了。</li>
</ol>
《Redis深度历险》学习笔记:管道&事务
https://acuario.xyz/posts/redis-deep-adventure-pipeline-and-transaction/
2023-09-27T18:25:39+00:00
2020-08-11T15:21:17+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="管道">管道</h2>
<ul>
<li>Redis 的管道特性由 Redis 客户端提供,客户端通过改变了读写的顺序带来性能的巨大提升。</li>
<li>Redis 的管道命令让客户端通过对管道中的指令列表改变读写顺序就可以大幅节省 IO 时间。</li>
<li>管道中指令越多,效果越好。</li>
<li>管道的本质:操作系统内核从为套接字分配的缓冲区(发送缓冲 send buffer / 接收缓冲 recv buffer)中读写数据。</li>
<li>执行命令时,系统会调用 write 和 read 进行 IO 操作:
<ul>
<li>write 操作只负责将数据写到本地操作系统内核的发送缓冲,如果发送缓冲满了,则等待缓冲相应就是写操作 IO 操作的真正耗时。</li>
<li>read 操作只负责将数据从本地操作系统内核的接收缓冲中取出,如果接收缓冲是空的,则等待数据到来就是读操作 IO 操作的真正耗时。</li>
</ul>
</li>
<li>对于管道来说,连续的 write 操作根本就没有耗时,之后第一个 read 操作会等待一个网络的来回开销,然后所有的响应消息就都已经回送到内核的读缓冲了,后续的 read 操作直接就可以从缓冲拿到结果,瞬间返回。</li>
<li><strong>管道不仅减少了 RTT,同时也减少了 IO 调用次数(IO 调用涉及到用户态到内核态之间的切换)</strong>。</li>
</ul>
<p><img src="https://i.loli.net/2020/08/11/3JzKEshZNQdlSiD.png" alt="传统请求相应模式"><br>
(Source: <a href="https://wenchao.ren/2019/07/redis-Pipeline/">被遗忘的站点</a>)</p>……
<h2 id="管道">管道</h2>
<ul>
<li>Redis 的管道特性由 Redis 客户端提供,客户端通过改变了读写的顺序带来性能的巨大提升。</li>
<li>Redis 的管道命令让客户端通过对管道中的指令列表改变读写顺序就可以大幅节省 IO 时间。</li>
<li>管道中指令越多,效果越好。</li>
<li>管道的本质:操作系统内核从为套接字分配的缓冲区(发送缓冲 send buffer / 接收缓冲 recv buffer)中读写数据。</li>
<li>执行命令时,系统会调用 write 和 read 进行 IO 操作:
<ul>
<li>write 操作只负责将数据写到本地操作系统内核的发送缓冲,如果发送缓冲满了,则等待缓冲相应就是写操作 IO 操作的真正耗时。</li>
<li>read 操作只负责将数据从本地操作系统内核的接收缓冲中取出,如果接收缓冲是空的,则等待数据到来就是读操作 IO 操作的真正耗时。</li>
</ul>
</li>
<li>对于管道来说,连续的 write 操作根本就没有耗时,之后第一个 read 操作会等待一个网络的来回开销,然后所有的响应消息就都已经回送到内核的读缓冲了,后续的 read 操作直接就可以从缓冲拿到结果,瞬间返回。</li>
<li><strong>管道不仅减少了 RTT,同时也减少了 IO 调用次数(IO 调用涉及到用户态到内核态之间的切换)</strong>。</li>
</ul>
<p><img src="https://i.loli.net/2020/08/11/3JzKEshZNQdlSiD.png" alt="传统请求相应模式"><br>
(Source: <a href="https://wenchao.ren/2019/07/redis-Pipeline/">被遗忘的站点</a>)</p>
<p><img src="https://i.loli.net/2020/08/11/uxETZ5iQqbGdXRY.png" alt="管道模式"><br>
(Source: <a href="https://wenchao.ren/2019/07/redis-Pipeline/">被遗忘的站点</a>)</p>
<p>下面分别对比了传统模式、管道模式、事务批量执行模式在命令时序方面的差异,可以看到利用 <code>批量执行</code> 或 <code>事务+管道</code> 可以实现很大的性能优化:</p>
<p><img src="https://i.loli.net/2020/08/11/KkDT52gaOMENn9I.png" alt="传统模式"><br>
(Source: <a href="http://taswar.zeytinsoft.com/redis-pipeline-batching/">Taswar BhattiTaswar Bhatti</a>)</p>
<p><img src="https://i.loli.net/2020/08/11/oB58bP3FYjcIUd1.png" alt="管道模式"><br>
(Source: <a href="http://taswar.zeytinsoft.com/redis-pipeline-batching/">Taswar BhattiTaswar Bhatti</a>)</p>
<p><img src="https://i.loli.net/2020/08/11/bN4hKHqQlUPJxVZ.png" alt="批量执行模式"><br>
(Source: <a href="http://taswar.zeytinsoft.com/redis-pipeline-batching/">Taswar BhattiTaswar Bhatti</a>)</p>
<h2 id="事务">事务</h2>
<ul>
<li>
<p>Redis 的事务模型很不严格,这要求我们不能像使用关系数据库的事务一样来使用 Redis。</p>
</li>
<li>
<p>Redis 的事务命令分别是:</p>
<ul>
<li><code>multi</code>:开始事务,相当于 <code>begin</code></li>
<li><code>exec</code>:执行事务,相当于 <code>commit</code></li>
<li><code>discard</code>:丢弃事务,不执行前序事务</li>
</ul>
</li>
<li>
<p>Redis 的事务仅仅是满足了事务的「隔离性」,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利:</p>
<pre tabindex="0"><code>> multi # 开始事务
OK
> set books iamastring
QUEUED
> incr books
QUEUED
> set poorman iamdesperate
QUEUED
> exec # 执行事务
1) OK
2) (error) ERR value is not an integer or out of range # 执行错误但会继续执行后续命令,并生效
3) OK
> get books
"iamastring"
> get poorman
"iamdesperate
> get books
(nil)
> multi # 开始事务
OK
> incr books
QUEUED
> incr books
QUEUED
> discard # 丢弃事务
OK
> get books
(nil)
</code></pre></li>
<li>
<p>使用 Redis 事务时通常需要执行较多的命令,一半会配合<code>管道</code>进行使用,以提高性能。</p>
</li>
<li>
<p>Redis 提供 <code>watch</code> 命令处理并发产生的竞争条件问题: 事务只能在所有<strong>被监视键都没有被修改的前提下执行</strong>,如不满足则不执行事务。</p>
</li>
<li>
<p><code>watch</code> 命令是乐观锁,在 <code>watch</code> 执行后,<code>exec</code> 执行前,如果被监视键的值改变,则事务执行失败。此时可重试事务操作,直到没有发生碰撞为止。大多数情况下,变量碰撞的情况很少,所以通常并不需要进行重试。</p>
<pre tabindex="0"><code>WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC # 如果 mykey 改变,则返回 null
</code></pre></li>
<li>
<p>Redis 不支持事务回滚 <code>rollback</code>,原因如下:</p>
<ul>
<li>Redis 是<strong>单线程</strong>服务,事务仅会因错误命令而执行失败。错误的命令应在开发的过程中被发现,而不应该出现在生产环境中。</li>
<li>实现回滚需要付出额外的开销和成本,这违背了 Redis 的设计哲学和生态。</li>
</ul>
</li>
</ul>
<p>延伸阅读:</p>
<ul>
<li><a href="https://wenchao.ren/2019/07/redis-Pipeline/">redis Pipeline - 被遗忘的站点</a></li>
<li><a href="https://redis.io/topics/pipelining">Using pipelining to speedup Redis queries – Redis</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/72867786">如何用好redis pipeline - 知乎</a></li>
<li><a href="https://redislabs.com/blog/you-dont-need-transaction-rollbacks-in-redis/">You Don’t Need Transaction Rollbacks in Redis | Redis Labs</a></li>
<li><a href="http://redisdoc.com/topic/transaction.html">事务(transaction) — Redis 命令参考</a></li>
<li><a href="http://taswar.zeytinsoft.com/redis-pipeline-batching/">Redis for .NET Developers – Redis Pipeline Batching | Taswar BhattiTaswar Bhatti</a></li>
</ul>
《Redis深度历险》学习笔记:线程模型&持久化
https://acuario.xyz/posts/redis-deep-adventure-thread-model-and-persistence/
2023-09-27T18:25:39+00:00
2020-08-10T22:24:55+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="线程模型">线程模型</h2>
<h3 id="非阻塞io">非阻塞IO</h3>
<ul>
<li>Redis、Node.js、Nginx 均是<strong>单线程</strong>服务,但他们都是服务器高性能的典范。</li>
<li>Redis 4.0 版本抛弃了单线程设计,转为多线程设计,但其<strong>主处理程序依然是单线程模型</strong>。</li>
<li>Redis 使用单线程进行设计的原因:
<ul>
<li>更好的可维护性,方便开发和调试:多线程模型存在竞争条件 (race condition)问题,多个进行的执行顺序会对共享内存的内容造成影响,需要额外设计锁逻辑。</li>
<li>处理并发请求:将数据库的开、关、读、写都转换成了事件,使用 <code>I/O 多路复用</code> 机制轮询描述符处理并发连接,同时等待多个连接发送的请求。</li>
<li>Redis 服务中运行的绝大多数操作的性能瓶颈都不是 CPU:一个 Redis 服务在 1s 内可处理 100w 个用户请求,如无法满足,应使用分片将不同的请求交给不同的 Redis 服务器来处理,而不是在同一个 Redis 服务中引入大量的多线程操作。</li>
</ul>
</li>
<li>每一个网络连接都会产生一个<code>文件描述符</code>,并由执行事件循环(死循环)的<code>多路复用</code>模块接收,然后关联指令队列,交给<code>文件事件分配器</code>按顺序处理。一旦期间有任何事件到来,就可以立即返回。时间过了之后还是没有任何事件到来,也会立即返回。
<img src="https://i.loli.net/2020/08/10/PBFLEw7Zv3tgzIa.jpg" alt="多路复用">
(Source: <a href="https://draveness.me/redis-io-multiplexing/">Redis 和 I/O 多路复用</a>)</li>
</ul>……
<h2 id="线程模型">线程模型</h2>
<h3 id="非阻塞io">非阻塞IO</h3>
<ul>
<li>Redis、Node.js、Nginx 均是<strong>单线程</strong>服务,但他们都是服务器高性能的典范。</li>
<li>Redis 4.0 版本抛弃了单线程设计,转为多线程设计,但其<strong>主处理程序依然是单线程模型</strong>。</li>
<li>Redis 使用单线程进行设计的原因:
<ul>
<li>更好的可维护性,方便开发和调试:多线程模型存在竞争条件 (race condition)问题,多个进行的执行顺序会对共享内存的内容造成影响,需要额外设计锁逻辑。</li>
<li>处理并发请求:将数据库的开、关、读、写都转换成了事件,使用 <code>I/O 多路复用</code> 机制轮询描述符处理并发连接,同时等待多个连接发送的请求。</li>
<li>Redis 服务中运行的绝大多数操作的性能瓶颈都不是 CPU:一个 Redis 服务在 1s 内可处理 100w 个用户请求,如无法满足,应使用分片将不同的请求交给不同的 Redis 服务器来处理,而不是在同一个 Redis 服务中引入大量的多线程操作。</li>
</ul>
</li>
<li>每一个网络连接都会产生一个<code>文件描述符</code>,并由执行事件循环(死循环)的<code>多路复用</code>模块接收,然后关联指令队列,交给<code>文件事件分配器</code>按顺序处理。一旦期间有任何事件到来,就可以立即返回。时间过了之后还是没有任何事件到来,也会立即返回。
<img src="https://i.loli.net/2020/08/10/PBFLEw7Zv3tgzIa.jpg" alt="多路复用">
(Source: <a href="https://draveness.me/redis-io-multiplexing/">Redis 和 I/O 多路复用</a>)</li>
</ul>
<ul>
<li>
<p>关于<code>异步</code>和<code>阻塞</code>的概念,<a href="https://www.adamfei.com/from-lao-zhang-and-kettle-to-understand-the-story-of-synchronous-asynchronous-blocking-and-non-blocking/">这篇文章</a>有一个形象的举例:</p>
<pre tabindex="0"><code>出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
同步阻塞:老张把水壶放到火上,立等水开。
同步非阻塞:老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。
异步阻塞:老张把响水壶放到火上,立等水开。
异步非阻塞:老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。
</code></pre></li>
</ul>
<h2 id="持久化">持久化</h2>
<h3 id="rdb-快照">RDB 快照</h3>
<ul>
<li>RDB 快照是一次全量备份,是内存数据的二进制序列化形式,在存储上非常紧凑。</li>
<li>持久化需要进行文件 IO,但该操作不能使用多路复用 API,在拖慢性能的同时,还存在数据一致性的问题(脏读、幻读等),为避免上述问题,Redis 使用多进程 COW(Copy On Write)策略进行持久化。</li>
<li>创建快照(持久化)时:
<ul>
<li>fork(多进程)函数使进程分离,产生父、子进程,双方共享内存数据,内存里的数据在进程产生的一瞬间就凝固。</li>
<li>父进程持续处理数据,复制需要修改的数据端后进行操作,不改变原有数据端。</li>
<li>子进程持续读取数据端内数据进行快照操作,读写数据到一个临时文件 RDB 中。</li>
<li>子进程完成读写后替换原 RDB 文件。</li>
</ul>
</li>
</ul>
<h3 id="aof-日志append-only-file">AOF 日志(Append-Only File)</h3>
<ul>
<li>AOF 日志是顺序指令序列,只记录对内存进行修改的指令记录。</li>
<li>Redis 通常<strong>先执行命令,再记录 AOF 日志</strong>。</li>
</ul>
<h4 id="aof-重写">AOF 重写</h4>
<ul>
<li>长期运行会使 AOF 日志文件过大,重放日志耗时过长,<code>AOF 重写</code>操作可为文件瘦身。</li>
<li>运行机制:
<ul>
<li>fork(多进程)函数使进程分离,产生父、子进程</li>
<li>子进程将日志写入到一个临时文件 AOF 中</li>
<li>父进程将数据变更写入到临时内存缓冲区,同时持续写入日志到原 AOF 文件中(这样即使断电,也能保证有一个 AOF 文件是可用的)</li>
<li>子进程完成读写后,父进程接收信号,将内存缓冲区日志追加到临时文件 AOF 中</li>
<li>父进程完成写入后替换 AOF 文件,从而实现 AOF 重写。</li>
</ul>
</li>
<li>AOF 日志使用 Linux 提供的 <code>fsync</code> 函数进行文件写入操作,但由于文件 IO 速度慢,需要设置适当的写入周期。</li>
<li>AOF 日志的 <code>fsync</code> 周期默认为 1s。(服务宕机最多丢失 1s 数据)。可关闭 <code>fsync</code> 牺牲安全性换取 Redis 性能。</li>
</ul>
<h3 id="redis-40-混合持久化">Redis 4.0 混合持久化</h3>
<ul>
<li>RDB 来恢复内存会丢失大量数据,通常使用 AOF 日志重放,为解决重放太耗时的问题,Redis 4.0 使用混合持久化。</li>
<li>将 RDB 文件和增量 AOF 日志文件存在一起,AOF 日志文件记录持久化过程中的增量变更。重放时,双管齐下甭提有多爽快了!</li>
</ul>
<hr>
<p>延伸阅读:</p>
<ul>
<li><a href="https://draveness.me/whys-the-design-redis-single-thread/">为什么 Redis 选择单线程模型 - 面向信仰编程</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/52600663">阿里P8架构师谈:Redis为什么是单线程、及高并发快的3大原因详解 - 知乎</a></li>
<li><a href="https://redislabs.com/blog/multiplexing-explained/">Multiplexing Explained | Redis Labs</a></li>
<li><a href="https://redis.io/topics/persistence">Redis Persistence – Redis</a></li>
</ul>
《Redis深度历险》学习笔记:Scan
https://acuario.xyz/posts/redis-deep-adventure-scan/
2023-09-27T18:25:39+00:00
2020-07-28T20:55:31+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h1 id="scan-命令">Scan 命令</h1>
<ul>
<li>使用 <code>keys</code> 命令来查找特定前缀的 key 列表有两个缺点:
<ul>
<li>没有 <code>offset</code>、<code>limit</code> 参数,该命令会一次性输出所有满足条件的结果。</li>
<li><code>keys</code> 命令的时间复杂度为 <code>O(n)</code>,大键查询会<strong>阻塞进程,造成卡顿</strong>。</li>
</ul>
</li>
<li>通常使用 <code>scan</code> 命令来进行大键查询:
<ul>
<li><code>scan</code> 命令的时间复杂度为 <code>O(n)</code>,但通过游标分步进行,<strong>不阻塞进程</strong>,游标的唯一状态为返回的游标整数。</li>
<li>提供 <code>limit</code> 参数,实际数量返回<strong>可多可少</strong>。</li>
<li><strong>返回结果可能有重复</strong>,需要自行去重。</li>
<li>遍历查询时若有数据变动,是否会返回符合条件的数据<strong>一切随缘</strong>。</li>
<li>返回为空不一定表示无结果,要看<strong>游标是否为零</strong>。</li>
</ul>
</li>
<li>Scan 命令可以用于各种类型数据的操作,如 <code>zscan</code> 用于 zset 集合、<code>hscan</code> 用于 hash 字典、<code>sscan</code> 用于 set 集合。</li>
<li>在集群环境下,如果某个 key 太大,会数据导致迁移卡顿。</li>
<li>在内存分配上,如果一个 key 太大,它扩容时会申请更大内存,导致卡顿。</li>
<li>开发中,要<strong>尽量避免大 key 的产生</strong>。</li>
</ul>……
<h1 id="scan-命令">Scan 命令</h1>
<ul>
<li>使用 <code>keys</code> 命令来查找特定前缀的 key 列表有两个缺点:
<ul>
<li>没有 <code>offset</code>、<code>limit</code> 参数,该命令会一次性输出所有满足条件的结果。</li>
<li><code>keys</code> 命令的时间复杂度为 <code>O(n)</code>,大键查询会<strong>阻塞进程,造成卡顿</strong>。</li>
</ul>
</li>
<li>通常使用 <code>scan</code> 命令来进行大键查询:
<ul>
<li><code>scan</code> 命令的时间复杂度为 <code>O(n)</code>,但通过游标分步进行,<strong>不阻塞进程</strong>,游标的唯一状态为返回的游标整数。</li>
<li>提供 <code>limit</code> 参数,实际数量返回<strong>可多可少</strong>。</li>
<li><strong>返回结果可能有重复</strong>,需要自行去重。</li>
<li>遍历查询时若有数据变动,是否会返回符合条件的数据<strong>一切随缘</strong>。</li>
<li>返回为空不一定表示无结果,要看<strong>游标是否为零</strong>。</li>
</ul>
</li>
<li>Scan 命令可以用于各种类型数据的操作,如 <code>zscan</code> 用于 zset 集合、<code>hscan</code> 用于 hash 字典、<code>sscan</code> 用于 set 集合。</li>
<li>在集群环境下,如果某个 key 太大,会数据导致迁移卡顿。</li>
<li>在内存分配上,如果一个 key 太大,它扩容时会申请更大内存,导致卡顿。</li>
<li>开发中,要<strong>尽量避免大 key 的产生</strong>。</li>
</ul>
<ul>
<li>假设 redis 中已经存在 10000 条名为 key%d 的数据,下面是一个 scan 的例子:</li>
</ul>
<pre tabindex="0"><code>127.0.0.1:6379> scan 0 match key99* count 1000
1) "13976"
2) 1) "key9911"
2) "key9974"
......
12) "key9905" // 扫描了 1000 个槽位,返回 12 条数据,还有库存
127.0.0.1:6379> scan 13976 match key99* count 1000
1) "1996"
2) (empty list or set) // 扫描了 1000 个槽位,返回为空,还有库存
127.0.0.1:6379> scan 1996 match key99* count 1000
1) "12594"
2) 1) "key9939"
2) "key9941"
...... // 扫描了 1000 个槽位,返回 N+ 条数据,还有库存
127.0.0.1:6379> scan 11687 match key99* count 1000
1) "0"
2) 1) "key9969"
2) "key998"
......
11) "key9944" // 扫描了 1000 个槽位,返回 11 条数据,游标为 0,没有库存啦
</code></pre><ul>
<li>可以使用 <code>--bigkeys</code> 参数定位大键:</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">redis-cli -h 127.0.0.1 -p <span class="m">7001</span> –-bigkeys
</span></span><span class="line"><span class="cl">redis-cli -h 127.0.0.1 -p <span class="m">7001</span> –-bigkeys -i 0.1 // i 为休眠参数,每隔 <span class="m">100</span> 条 scan 指令就会休眠 0.1s
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="字典结构">字典结构</h1>
<ul>
<li>
<p>字典结构的特殊性决定了 Scan 的高效,游标返回的是槽位号码,每个槽位(slot)挂载的元素可多可少,所以有可能出现返回结果为空的情况:</p>
<p><img src="https://i.loli.net/2020/07/28/b7jxP6TZWLnlRNG.png" alt="字典结构">
<img src="https://i.loli.net/2020/07/28/BC2lRMsypU5DXku.png" alt="字典结构"></p>
</li>
<li>
<p>scan 命令以高位进位加法进行检索,与普通加法相反,但也可以遍历所有结果:</p>
<p><img src="https://redis-1253868755.cos.ap-guangzhou.myqcloud.com/redis-scan-high-carry.gif" alt="高位进位加法"></p>
</li>
</ul>
<h1 id="字典扩容">字典扩容</h1>
<ul>
<li>
<p>数组长度为 <code>2^n</code> 次方,所以取模运算等价于位与操作,<code>a mod 8 = a & (8-1) = a & 7</code>,7 称为字典的 <code>mask</code> 值。扩容操作使得原槽位 <code>xxx</code> 中的一半数据不变还是 <code>0xxx</code> ,另一半放到了 <code>1xxx(xxx+mask)</code> 中:</p>
<p><img src="https://redis-1253868755.cos.ap-guangzhou.myqcloud.com/redis-scan-rehash.png" alt="字典扩容"></p>
</li>
<li>
<p>这样的字典伸缩方式使得 scan 按高位加法遍历数组变得无比高效,因为伸缩操作此时对 scan 的遍历方法毫无影响!<strong>rehash 后的槽位在遍历时的顺序依然是相邻的!!</strong></p>
<p><img src="https://redis-1253868755.cos.ap-guangzhou.myqcloud.com/redis-scan-cap-change.png" alt="字典伸缩遍历"></p>
</li>
<li>
<p>渐进式 rehash 会同时保留旧数组和新数组,在定时任务中以及后续对 hash 的指令操作中渐渐地将旧数组中挂接的元素迁移到新数组上,避免大键伸缩造成卡顿</p>
</li>
<li>
<p>scan 处于 rehash 中的字典,需要同时扫描新旧槽位,然后将结果融合后返回给客户端</p>
</li>
</ul>
《Redis深度历险》学习笔记:GeoHash
https://acuario.xyz/posts/redis-deep-adventure-geohash/
2023-09-27T18:25:39+00:00
2020-05-24T17:39:00+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p><img src="https://i.loli.net/2020/05/24/STvYDkfc45O8ReM.png" alt=""></p>
<ul>
<li>
<p>经纬度坐标使用关系数据库 (元素 id, 经度 x, 纬度 y) 存储,可以指定一个半径 r 使用一条 SQL 圈出一定范围内的元素。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">positions</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">x0</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">x0</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">r</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">y0</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">y0</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">r</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。</p>
</li>
<li>
<p>映射算法实际是对地图进行精细切分,然后对这些方格进行整数编码。编码后每个地图元素的坐标都将变成一个整数,越是靠近的方格编码越是接近。</p>
</li>
</ul>……
<p><img src="https://i.loli.net/2020/05/24/STvYDkfc45O8ReM.png" alt=""></p>
<ul>
<li>
<p>经纬度坐标使用关系数据库 (元素 id, 经度 x, 纬度 y) 存储,可以指定一个半径 r 使用一条 SQL 圈出一定范围内的元素。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">positions</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">x0</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">x0</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">r</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">y0</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">y0</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">r</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。</p>
</li>
<li>
<p>映射算法实际是对地图进行精细切分,然后对这些方格进行整数编码。编码后每个地图元素的坐标都将变成一个整数,越是靠近的方格编码越是接近。</p>
</li>
</ul>
<ul>
<li>切分时使用二进制整数表示方格,如(00,01,10,11),精度越高,二进制整数越长。编码之后,每个地图元素的坐标都将变成一个整数。GeoHash 算法会继续对这个整数做一次 <code>base32</code> 编码成一个字符串,使用 zset 的 <code>value-score</code> 结构进行存储。<code>value</code> 储存元素的 key,<code>score</code> 储存元素的 52 位整数值。</li>
<li>Redis 的 Geo 数据结构,它们将全部放在一个 zset 集合中,在集群环境中单个 key 对应的数据量不宜超过 <code>1M</code>,否则会导致集群迁移出现
卡顿现象,影响线上服务的正常运行。</li>
<li>建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。如果数据量过大,需要对 Geo 数据按适合维度进行拆分。</li>
<li>Redis 的 GeoHash 只有 6 个基本指令,<strong>没有</strong>提供 geo 删除指令:</li>
</ul>
<pre tabindex="0"><code># 增加元素
127.0.0.1:6379> geoadd company 116.48105 39.996794 juejin
(integer) 1
127.0.0.1:6379> geoadd company 116.562108 39.787602 jd 116.334255 40.027400 xiaomi
(integer) 2
# 获取两元素间距离,距离单位可以是 m、km、ml、ft
127.0.0.1:6379> geodist company juejin ireader km
"10.5501"
# 获取元素位置
127.0.0.1:6379> geopos company ireader
1) 1) "116.5142020583152771"
2) "39.90540918662494363"
127.0.0.1:6379> geopos company juejin ireader
1) 1) "116.48104995489120483"
2) "39.99679348858259686"
2) 1) "116.5142020583152771"
2) "39.90540918662494363"
# 获取元素的 hash 值
# 可以使用这个编码值去 http://geohash.org/${hash}中进行直接定位
127.0.0.1:6379> geohash company ireader
1) "wx4g52e1ce0"
# 根据元素查询附近元素(不会排除自身)
# 范围 20 公里以内最多 3 个元素按距离正排
127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 asc
1) "ireader"
2) "juejin"
3) "meituan"
# 范围 20 公里以内最多 2 个元素按距离正排,并显示距离、哈希值、坐标
127.0.0.1:6379> georadiusbymember company ireader 20 km withcoord withdist withhash count 2 asc
1) 1) "ireader"
2) "0.0000"
3) (integer) 4069886008361398
4) 1) "116.5142020583152771"
2) "39.90540918662494363"
2) 1) "juejin"
2) "10.5501"
3) (integer) 4069887154388167
4) 1) "116.48104995489120483"
2) "39.99679348858259686"
# 根据坐标值查询附近的元素
127.0.0.1:6379> georadius company 116.514202 39.905409 20 km withdist count 2 asc
1) 1) "ireader"
2) "0.0000"
2) 1) "juejin"
2) "10.5501"
</code></pre>
《Redis深度历险》学习笔记:HyperLogLog&布隆过滤器
https://acuario.xyz/posts/redis-deep-adventure-hyperloglog-and-bloom-filter/
2023-09-27T18:25:39+00:00
2020-05-12T00:31:17+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="hyperloglog">HyperLogLog</h2>
<ul>
<li>通常用来统计一个集合中不重复的元素个数的方法叫做<strong>基数计数</strong>(cardinality counting)。(eg. 统计页面 UV)</li>
<li>HyperLogLog 是 Redis 的高级数据结构,用来解决使用 set 结构进行基数计数时占用空间过大的问题。</li>
<li>HyperLogLog 统计的标准误差为 0.81%</li>
</ul>……
<h2 id="hyperloglog">HyperLogLog</h2>
<ul>
<li>通常用来统计一个集合中不重复的元素个数的方法叫做<strong>基数计数</strong>(cardinality counting)。(eg. 统计页面 UV)</li>
<li>HyperLogLog 是 Redis 的高级数据结构,用来解决使用 set 结构进行基数计数时占用空间过大的问题。</li>
<li>HyperLogLog 统计的标准误差为 0.81%</li>
</ul>
<ul>
<li>HyperLogLog 结构的发明人是 Philippe Flajolet,故 HyperLogLog 命令以其名字首字母缩写 <code>pf</code> 开头:
<ul>
<li><code>pfadd</code>:向键内增加元素,并去重。</li>
<li><code>pfcount</code>:统计键内元素数量。</li>
<li><code>pfmerge</code>:将多个 pf 计数值累加在一起形成一个新的 pf 值。适用于合并相似统计项的数值,即 <code>A+B</code>。</li>
</ul>
<pre tabindex="0"><code>127.0.0.1:6379> pfadd codehole user1
(integer) 1
127.0.0.1:6379> pfadd codehole user2
(integer) 1
127.0.0.1:6379> pfadd codehole user1
(integer) 0
127.0.0.1:6379> pfcount codehole
(integer) 2
</code></pre></li>
<li>HyperLogLog 计数较小时,采用<strong>稀疏矩阵</strong>存储,空间占用很小,计数超过了阈值时转变成<strong>稠密矩阵</strong>,占用 12KB 的空间。数据量大时性价比明显优于 set 结构。</li>
<li>一个 pf 项占用内存空间 <code>12KB</code>。</li>
<li>HyperLogLog 不储存元素本身,<strong>不能</strong>像 set 那样返回输入的元素。</li>
</ul>
<h3 id="原理">原理</h3>
<ul>
<li>
<p>HyperLogLog 是个神奇的算法,它的精髓有 2 点:</p>
<ul>
<li>恰当的哈希算法对数据的处理可以使数据分布均匀。这一点类似于投足够多次硬币,某一面朝上的概率能够均匀分布在 50% 附近(也就是概率论中的伯努利分布)</li>
<li>对于一个乱序集合,如果元素的哈希值末尾出现的 0 的个数记为 <code>k</code>,那么观察所有元素的 <code>k</code> 值,其中最大值 <code>K</code> 与集合内元素的总数量 <code>N</code> 有相关性:<code>N = 2^K</code>。<br>
eg. 有 1-37600 的数字随机排列,取出一些数字来进行哈希计算,找出二进制值末尾出现的 0 的最大的个数,发现 K=15 —— <code>2^15 = 32768</code></li>
</ul>
</li>
<li>
<p>上面还是有点抽象,为什么末尾 0 的个数可以与集合内元素总数相关,想了很久才有了一点眉目,干脆用这个不恰当的栗子来理解好了:</p>
<ul>
<li><code>假如有一个骰子,如何通过实验来获知这个骰子上有几种不同的图案?</code><br>
其实方法很简单,只需要<code>每投一次就记录一下图案,投足够多次,就可以知道每种图案出现的概率,然后大概就能猜出总共有几种图案。</code><br>
这有点像通过查看投硬币的结果来猜测硬币有 2 面而不是 3 面。</li>
<li>HyperLogLog 中的哈希算法对数据的处理,保证了哈希结果是均匀随机的,即保证了「投币」的随机性。</li>
</ul>
</li>
<li>
<p><a href="http://blog.notdot.net/2012/09/Dam-Cool-Algorithms-Cardinality-Estimation">这篇文章</a>描述了算法的基本原理——要统计一个数据集合 <code>values</code> 的不重复元素总数时:</p>
<ol>
<li>对元素做哈希计算,获得元素的哈希值 <code>h</code></li>
<li>哈希值 <code>h</code> 的前几位当作桶 <code>bucket</code> 的编号 <code>n</code>,其余部分 <code>bucket_hash</code> 放入桶中</li>
<li>查看桶中的值末尾有几个 0,与记录中的最多末尾 0 标志 <code>max_zeroes</code> 进行比较,并更新 <code>max_zeroes</code></li>
<li>遍历 <code>values</code>,对每个元素重复 1-3 步</li>
</ol>
</li>
<li>
<p>Redis 的 HyperLogLog 算法采用 <code>2^14=16384</code> 个桶进行独立计数(原始算法为 1024 个),每个桶使用 <code>6bit</code> 来保存当前桶低位连续零位的最大长度 <code>max_zeroes</code>(最大可表示 2^6-1=63),所以一个 pf 项占用内存空间 <code>2^14 * 6Kbit = 98Kbit = 12KByte</code>。</p>
</li>
</ul>
<h2 id="布隆过滤器">布隆过滤器</h2>
<ul>
<li>布隆过滤器(Bloom Filter)由布隆于 1970 年提出,它是一个很长的二进制向量和一系列随机映射函数,用于<strong>检索一个元素是否在一个集合中</strong>。</li>
<li>布隆过滤器原理:
<ul>
<li>使用 hash 算法对数据进行计算,将其结果对应位置(如1,4,5)设为 1。</li>
<li>验证时对对象进行 hash 计算后查看对应位(如1,4,5)是否<strong>都</strong>为 1。</li>
<li>受制于空间大小,多个数据的 hash 结果可能重叠,导致验证存在性时的误判。</li>
</ul>
</li>
</ul>
<p><img src="https://i.loli.net/2020/05/05/jZSwOybJFxlLq7B.png" alt="布隆过滤器"></p>
<ul>
<li>布隆过滤器的空间效率和查询时间都<strong>远超一般算法</strong>,但存在一定的<strong>误识别率</strong>和<strong>删除困难</strong>。</li>
<li>布隆过滤器是一个不够精确的 set 结构,返回 <code>true</code> 时真实结果<strong>可能为</strong> <code>false</code>,返回 <code>false</code> 时真实结果<strong>一定为</strong> <code>false</code>。</li>
<li>通常使用 3 个基本命令:
<pre tabindex="0"><code># 添加元素
127.0.0.1:6379> bf.add codehole user1
(integer) 1
# 批量添加元素
127.0.0.1:6379> bf.madd codehole user2 user3
1) (integer) 1
2) (integer) 1
# 查询元素是否存在
127.0.0.1:6379> bf.exists codehole user1
(integer) 1
# 批量查询元素是否存在
127.0.0.1:6379> bf.mexists codehole user2 user3 user4
1) (integer) 1
2) (integer) 1
3) (integer) 0
</code></pre></li>
<li><code>bf.reserve {key} {error_rate} {capacity}</code> 命令(<a href="https://oss.redislabs.com/redisbloom/Bloom_Commands/">文档</a>)可以显式创建布隆过滤器(重复创建时会报错),该命令有 3 个参数:
<ul>
<li><code>key</code>:过滤器键名。</li>
<li><code>error_rate</code>:错误率。错误率越低,所需空间越大。对于非精确场合可设置较大值。</li>
<li><code>capacity</code>:预计放入的元素数量。当实际数量超出这个数值时,误判率会上升。该值估计的过大,会浪费存储空间,估计的过小,就会影响准确率。</li>
</ul>
</li>
<li>使用布隆过滤器时不要让实际元素远大于初始化大小,超出时应重建过滤器、分配更大 size 的过滤器,并导入所有历史元素 (需提前在外部保存历史元素)。</li>
<li><code>error_rate</code> 不会因溢出而剧增,故重建过滤器的时间较为宽松,但也应提前合理设置。</li>
<li>爬虫系统中过滤爬虫的 URL 非常适合使用布隆过滤器来统计,进而大幅降低去重存储消耗。</li>
<li>布隆过滤器可以显著降低 DB 的 IO 请求数,在 NoSQL DB 领域使用广泛。</li>
<li>垃圾邮件过滤功能也普遍用到了布隆过滤器,故正常邮件会被误判。</li>
<li>用于计算布隆过滤器最佳参数的<a href="https://krisives.github.io/bloom-calculator/">布隆计算器</a></li>
</ul>
<p>延伸阅读:</p>
<ul>
<li><a href="https://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html">布隆过滤器 (Bloom Filter) 详解</a></li>
<li><a href="https://juejin.im/post/5cfd060ee51d4556f76e8067">Redis 高级主题之布隆过滤器(BloomFilter)</a></li>
<li>布谷鸟过滤器(Cuckoo Filter):<a href="https://oss.redislabs.com/redisbloom/Cuckoo_Commands/">官方文档</a> & <a href="https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf">相关论文</a></li>
</ul>
《Redis深度历险》学习笔记:位图
https://acuario.xyz/posts/redis-deep-adventure-bitmap/
2023-09-27T18:25:39+00:00
2020-05-06T00:21:17+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li>
<p>对于开关 / 签到类型的业务数据,可以考虑采用 <code>bitmap</code>(即<strong>位图</strong>)的数据结构进行存储</p>
</li>
<li>
<p>位图的最小单元是 <code>bit</code>,每个 bit 的取值只能是 0 或 1,如下图所示:<br>
<img src="https://i.loli.net/2020/04/24/vRyBwAUuJIbqsi6.png" alt="位图"></p>
</li>
<li>
<p>Redis 字符位顺序与其 ASCII 码二进制值位顺序相反,多个字符会自动扩容连接在一起:<br>
<img src="https://i.loli.net/2020/04/24/hZYvBUcOTCs7kwX.png" alt="image.png">
<img src="https://i.loli.net/2020/04/24/xJyfkbHUGzgFPpZ.png" alt="image.png"></p>
</li>
</ul>……
<ul>
<li>
<p>对于开关 / 签到类型的业务数据,可以考虑采用 <code>bitmap</code>(即<strong>位图</strong>)的数据结构进行存储</p>
</li>
<li>
<p>位图的最小单元是 <code>bit</code>,每个 bit 的取值只能是 0 或 1,如下图所示:<br>
<img src="https://i.loli.net/2020/04/24/vRyBwAUuJIbqsi6.png" alt="位图"></p>
</li>
<li>
<p>Redis 字符位顺序与其 ASCII 码二进制值位顺序相反,多个字符会自动扩容连接在一起:<br>
<img src="https://i.loli.net/2020/04/24/hZYvBUcOTCs7kwX.png" alt="image.png">
<img src="https://i.loli.net/2020/04/24/xJyfkbHUGzgFPpZ.png" alt="image.png"></p>
</li>
</ul>
<ul>
<li>
<p><code>set</code> 整存,<code>get</code> 整取,<code>setbit</code> 零存,<code>getbit</code> 零取:</p>
<pre tabindex="0"><code>127.0.0.1:6379> set w he
127.0.0.1:6379> get w
"he"
127.0.0.1:6379> setbit s 1 1
127.0.0.1:6379> setbit s 2 1
127.0.0.1:6379> setbit s 4 1
127.0.0.1:6379> setbit s 9 1
127.0.0.1:6379> setbit s 10 1
127.0.0.1:6379> setbit s 13 1
127.0.0.1:6379> setbit s 15 1
127.0.0.1:6379> getbit w 4
(integer) 1
127.0.0.1:6379> get s
"he"
</code></pre></li>
<li>
<p><code>bitcount</code> 命令统计指定位置范围内 1 的个数。<br>
eg. 统计签到天数。起始参数 <code>[start, end]</code> 为索引值,必须为 8 的倍数。</p>
</li>
<li>
<p><code>bitpos</code> 命令查找指定范围内出现的第一个 0 或 1。<br>
eg. 查找签到第一天。起始参数 <code>[start, end]</code> 为索引值,必须为 8 的倍数。</p>
</li>
<li>
<p><code>bitfield</code> 可以一次操作多个位,子指令 <code>get</code>/<code>set</code>/<code>incrby</code> 都可以对指定位片段进行读写,参数 <code>u</code> 为无符号,参数 <code>i</code> 为有符号。</p>
</li>
<li>
<p><code>bitfield</code> 处理上限为 64 个连续的位,否则需要执行子指令:</p>
<pre tabindex="0"><code>127.0.0.1:6379> bitfield w get u4 0 get u3 2 get i4 0 get i3 2
1) (integer) 6 #index=0,无符号取 4 位
2) (integer) 5 #index=2,无符号取 3 位
3) (integer) 6 #index=0,有符号取 4 位
4) (integer) -3 #index=2,有符号取 3 位,注意负数的补码计算
</code></pre></li>
<li>
<p>Redis 的 integer 是有符号数,最大 64 位,不能传递 64 位无符号值,所以<strong>无符号值最大值为 63 位</strong>。</p>
</li>
<li>
<p>自增操作需要注意位数据溢出的问题:</p>
<ul>
<li>无符号数自增溢出归零(eg. <code>u127+1=0</code>)</li>
<li>有符号数自增溢出变为最小负数(eg.<code>i127+1=-128</code>)</li>
</ul>
</li>
<li>
<p><code>bitfield</code> 提供另外两种溢出策略:</p>
<ul>
<li>饱和截断 SAT:停留在最大/最小值。</li>
<li>失败不执行 FAIL:报错不执行。</li>
</ul>
</li>
</ul>
《Redis深度历险》学习笔记:分布式锁&消息队列
https://acuario.xyz/posts/redis-deep-adventure-distributed-lock-and-queue/
2023-09-27T18:25:39+00:00
2020-04-24T23:06:45+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="分布式锁">分布式锁</h2>
<ul>
<li>分布式锁类似数据库锁,都是为了解决并发时非原子操作导致的问题而设计的。</li>
<li>设置分布式锁一般使用 <code>setnx</code>(set if not exists) 指令,调用 <code>del</code> 指令释放:
<pre tabindex="0"><code>SETNX mykey "Hello"
del mykey
</code></pre></li>
</ul>……
<h2 id="分布式锁">分布式锁</h2>
<ul>
<li>分布式锁类似数据库锁,都是为了解决并发时非原子操作导致的问题而设计的。</li>
<li>设置分布式锁一般使用 <code>setnx</code>(set if not exists) 指令,调用 <code>del</code> 指令释放:
<pre tabindex="0"><code>SETNX mykey "Hello"
del mykey
</code></pre></li>
</ul>
<ul>
<li><code>上锁->解锁</code> 过程中可能死锁,故使用 <code>expire</code> 命令加入过期时间:<code>上锁->设置过期->解锁</code>:
<pre tabindex="0"><code>SETNX mykey "Hello"
expire mykey 5
del mykey
</code></pre></li>
<li><code>上锁->设置过期</code> 过程中可能死锁,Redis 2.8 之后 <code>setnx</code> 命令和 <code>expire</code> 命令可以一起作为原子操作执行(其中的 <code>NX</code> 即为 <code>SETNX</code> 的最新实现),这也是目前 Redis 官方推荐使用的 <a href="https://redis.io/topics/distlock"><strong>Redlock</strong></a> 方式:
<pre tabindex="0"><code>set mykey "Hello" EX 5 NX
del mykey
</code></pre></li>
</ul>
<h3 id="超时问题">超时问题</h3>
<h4 id="问题原因">问题原因</h4>
<p>如图所示,如果 Client 1 的执行时间超过了自己设置的锁过期时间,则该锁可能会被其他程序持有,产生数据异常:</p>
<p><img src="https://martin.kleppmann.com/2016/02/unsafe-lock.png" alt="分布式锁超时问题">
(Source: <a href="http://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html">How to do distributed locking</a>)</p>
<h4 id="解决方案">解决方案</h4>
<ol>
<li>
<p>分布式锁不要用于较长时间的任务</p>
</li>
<li>
<p>为 set 指令的 value 参数设置为一个随机数,释放锁时先匹配随机数是否一致,然后再删除 key。使用 Lua 脚本将匹配 key 和 del 操作作为原子操作执行:</p>
<pre tabindex="0"><code>if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
</code></pre></li>
</ol>
<h3 id="可重入性">可重入性</h3>
<ul>
<li>可重入性是指线程在持有锁的情况下<strong>再次请求加锁</strong>。</li>
<li>Redis 可重入分布式锁要求包装客户端的 set 方法,使用线程的 Threadlocal 变量存储当前持有锁的计数。</li>
<li>由于可重入分布式锁会加重程序复杂性,一般建议优化代码逻辑,避免使用可重入分布式锁。</li>
</ul>
<h3 id="锁冲突">锁冲突</h3>
<p>由于锁冲突导致无法成功加锁的情况,可以使用以下 3 种策略来处理客户端加锁失败的情况:</p>
<ul>
<li>直接抛出异常:本质上是对当前请求的放弃,由用户决定是否重新发起新的请求。适合由用户直接发起的请求。</li>
<li>sleep:会导致队列的后续消息处理出现延迟。死锁的 key 加锁失败会堵死线程。适合碰撞少 / 消息少的场景。</li>
<li>延时队列:加入延时队列稍后重试。适合异步消息处理,避免冲突。</li>
</ul>
<h2 id="消息队列">消息队列</h2>
<ul>
<li>Redis 队列适用于只有一组队列消息消费者的情况。</li>
<li>Redis 的消息队列功能简单,没有太多高级特性。</li>
<li>Redis 的消息队列没有 ack 保证,消息可靠性不足,适用于数据敏感性不强的场景。</li>
</ul>
<h3 id="异步消息队列">异步消息队列</h3>
<ul>
<li>通常使用 <code>list</code> 结构来实现异步消息队列。</li>
<li>使用 <code>rpush</code>/<code>lpush</code> 命令入队列,<code>lpop</code>/<code>rpop</code> 命令出队列。</li>
</ul>
<p><img src="https://i.loli.net/2020/04/19/xeiTUPG6waZmbNA.png" alt="Redis队列"></p>
<h3 id="空队列">空队列</h3>
<h4 id="问题原因-1">问题原因</h4>
<p>队列为空时,客户端会陷入 pop 死循环的空轮询。空轮询会增加系统负载和 Redis 的 QPS,大大降低 Redis 的查询效率。</p>
<h4 id="解决方案-1">解决方案</h4>
<ol>
<li>线程闲置:使用 sleep 让线程闲置,降低轮询频率。</li>
<li>队列延迟:使用 <code>blpop</code>/<code>brpop</code> 阻塞读命令(b-blocking)替代 <code>lpop</code>/<code>rpop</code> 作为消息消费者接受数据的方法,在队列没有数据的时候,会立即进入休眠状态。</li>
</ol>
<p>ps. 线程阻塞时,Redis 客户端连接成为闲置连接,闲置超时会被服务器主动断开连接,导致阻塞读异常。使用时注意完善异常捕获和重连机制。</p>
<h3 id="延时消息队列">延时消息队列</h3>
<ul>
<li>通常使用 <code>zset</code> 来实现延时消息队列。</li>
<li>将消息序列化成字符串作为 <code>zset</code> 的 <code>value</code>,消息的到期处理时间作为 <code>score</code>,使用多线程轮询获取到期的任务进行处理。</li>
<li>多线程需要考虑并发争抢问题,通过 <code>zrem</code> 来决定唯一的属主,确保任务不能被多次执行:
<pre tabindex="0"><code>success = redis.zrem("delay-queue", value)
</code></pre></li>
<li>另外注意异常捕获,避免因为个别任务处理问题导致循环异常退出。</li>
</ul>
<h3 id="pubsub">PubSub</h3>
<ul>
<li>
<p>Redis 消息队列<strong>不支持消息的多播机制</strong>,<code>PubSub</code>(PublisherSubscriber,发布者订阅者模型)是 Redis 实现多播模式的模块。</p>
</li>
<li>
<p>客户端发起订阅命令,获得订阅成功通知后,即可收到生产者发布的信息。如果当前没有消息,会返回空,所以 PubSub 默认不是阻塞的。可以使用 listen 来阻塞监听消息来进行处理。</p>
</li>
<li>
<p>Redis 不允许连接在 subscribe 等待消息时进行其它的操作。</p>
<pre tabindex="0"><code>> subscribe codehole.image codehole.text # 同时订阅 2 个主题
馈信息
1) "subscribe"
2) "codehole.image"
3) (integer) 1
1) "subscribe"
2) "codehole.text"
3) (integer) 2
> psubscribe codehole.* # 模式匹配订阅
以收到
1) "psubscribe"
2) "codehole.*"
3) (integer) 1
> publish codehole.image https://www.google.com/dudo.png
(integer) 1
> publish codehole.text " 你好,欢迎加入码洞 "
(integer) 1
> publish codehole.blog '{"content": "hello, everyone", "title": "welcome"}'
(integer) 1
</code></pre></li>
<li>
<p>PubSub 消费者接收的消息格式形如:</p>
<pre tabindex="0"><code>{
'pattern': None,
'type': 'message',
'channel': 'codehole',
'data': 'python comes'
}
</code></pre><ul>
<li><code>data</code>:消息内容。字符串格式。</li>
<li><code>channel</code>:订阅的主题名称。</li>
<li><code>type</code>:消息类型。普通消息为 message;控制消息为 subscribe;模式订阅的反馈为 psubscribe;取消订阅指令为 unsubscribe 和 punsubscribe。</li>
<li><code>pattern</code>:订阅模式。通过 subscribe 指令订阅的主题,该字段为空。</li>
</ul>
</li>
<li>
<p>PubSub 的槽点比较致命,<strong>一般不推荐将 PubSub 应用于消息队列场景</strong>:</p>
<ul>
<li>生产者传递消息时,如果没有对应消费者,消息将被丢弃。</li>
<li>PubSub 的消息不会持久化,如果消费者宕机导致没有及时接收到,则将丢失消息。</li>
</ul>
</li>
</ul>
《Redis深度历险》学习笔记:介绍&基础数据结构
https://acuario.xyz/posts/redis-deep-adventure-intro/
2023-09-27T18:25:39+00:00
2020-04-19T17:50:46+08:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="介绍">介绍</h2>
<ul>
<li>Redis(<strong>Re</strong>mote <strong>Di</strong>ctionary <strong>S</strong>ervice),由意大利人 Salvatore Sanfilippo(网名Antirez)开发。</li>
<li>Redis 默认端口 <code>6379</code> 是「MERZ」一词在手机九宫格键盘上对应的数字位置。「MERZ」在 Antirez 的朋友圈语言中是「愚蠢」的代名词,它源于意大利广告女郎「Alessia Merz」在电视节目上说了一堆愚蠢的话。</li>
</ul>……
<h2 id="介绍">介绍</h2>
<ul>
<li>Redis(<strong>Re</strong>mote <strong>Di</strong>ctionary <strong>S</strong>ervice),由意大利人 Salvatore Sanfilippo(网名Antirez)开发。</li>
<li>Redis 默认端口 <code>6379</code> 是「MERZ」一词在手机九宫格键盘上对应的数字位置。「MERZ」在 Antirez 的朋友圈语言中是「愚蠢」的代名词,它源于意大利广告女郎「Alessia Merz」在电视节目上说了一堆愚蠢的话。</li>
</ul>
<h2 id="基础数据结构">基础数据结构</h2>
<h3 id="string-字符串">string (字符串)</h3>
<ul>
<li>字符数组 <code>key <-> value</code>。</li>
<li>通常将用户信息结构体使用 JSON 序列化成字符串存入 Redis,取用数据时反序列化。</li>
<li>string 型是动态字符串,可修改,最大长度为 512M。</li>
<li>通常采用加倍扩容预分配原则,减少内存的频繁分配:<br>
<code><1MB</code> 时翻倍扩容,<code>>1MB</code> 时每次扩容 <code>1MB</code>。</li>
<li>如果 string 已经设置了过期时间,但调用 set 方法修改后,过期时间会失效。</li>
</ul>
<h3 id="list-列表">list (列表)</h3>
<ul>
<li>列表是<strong>链表</strong>而不是数组,增删速度很快(<code>O(1)</code>),但索引定位很慢(<code>O(n)</code>)。</li>
<li>列表的底层结构为**<code>连续内存存储(ziplist) + 链表(linkedlist)</code>** 的混合结构 <strong><code>quicklist</code></strong>,既满足快速增删,又减少空间冗余。</li>
</ul>
<p><img src="https://i.loli.net/2020/03/06/6F5N1GlCnDTQYLU.png" alt="list"></p>
<ul>
<li>列表常用来做异步队列使用,实现队列、栈等结构。</li>
</ul>
<h3 id="hash-哈希">hash (哈希)</h3>
<ul>
<li>hash 是无序字典,底层结构为 <code>数组 + 链表</code>。</li>
<li>hash 字典的值只能是字符串。</li>
<li>hash 字典采用渐进式 rehash 策略来保证高性能,避免堵塞。创建新表进行 rehash,旧表持续可读,rehash 完成后删除旧表。</li>
<li>hash 字典可以对用户结构中的每个字段单独存储,方便部分获取,避免全量获取导致的资源浪费。</li>
<li>hash 结构的存储消耗高于单个字符串,使用时需考虑成本。</li>
</ul>
<p><img src="https://i.loli.net/2020/04/12/1sIvXOhP9EkBda8.png" alt="rehash"></p>
<h3 id="set-集合">set (集合)</h3>
<ul>
<li>set 内部的键值对是无序的唯一的,相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL。</li>
<li>移除最后一个元素后,set 自动被删除,内存被回收。</li>
<li>由于 set 键值具有唯一性,所以有去重功能。</li>
</ul>
<h3 id="zset-有序集合">zset (有序集合)</h3>
<ul>
<li>zset 为有序列表,可对 value 指定权重值 score 后进行排序。</li>
<li>zset 内部数据结构是「跳跃列表」,为支持随机的增删,使用了类似金字塔结构:底层元素串连,抽取代表值使用一级指针串连,抽取代表值使用二级指针串连……以此类推,最多 32 层。单个节点可能身兼多级职能。</li>
<li>跳跃列表采取随机策略来决定新元素的层级位置,层级概率逐级减半:L0 层概率 100%,L1 层 50%,L2 层 25%……</li>
</ul>
<p><img src="https://i.loli.net/2020/04/12/1clvxHgUIfi8hy5.png" alt="zset跳跃列表结构"></p>
<h2 id="容器型数据结构的通用规则">容器型数据结构的通用规则</h2>
<ul>
<li><code>list</code>/<code>set</code>/<code>hash</code>/<code>zset</code> 是<code>容器型数据结构</code>。</li>
<li>规则一:<code>create if not exists</code>——如果容器不存在,则先创建新容器再进行操作。
Redis 就会自动创建一个,然后再 rpush 进去新元素。</li>
<li>规则二:<code>drop if no elements</code>——如果容器内无元素,则立即删除容器,释放内存。</li>
<li>Redis 设置的<code>过期时间</code>是以对象为单位,而非元素/属性。即 hash 结构过期是整个 hash 对象的过期,并非子 key 过期。</li>
</ul>
《写真的思考》读书笔记
https://acuario.xyz/others/interpretation-on-hotographic-art-clip/
2023-09-27T18:25:39+00:00
2020-01-21T23:36:00+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="读后感">读后感</h2>
<p>对摄影评论并不是热衷,不过在这本饭泽耕太郎《写真的思考:摄影的存在意义》里,作者传达了一个容易被忽视的审美角度——有的摄影作品是“以偶然的方式处理偶然,并将其必然化”。这里所说的偶然,毫无疑问指的是摄影行为本身的偶然,而所谓的必然,其实是摄影行为在凝结为摄影作品后,呈现给观众的必然。将「偶然」作为摄影行为的动机,是刻意扰乱意识性的控制、主动地选取错乱的过程。这在摄影创作中并不少见,但我们往往习以为常,而忽略了它作为摄影动机的深刻内涵。</p>……
<h2 id="读后感">读后感</h2>
<p>对摄影评论并不是热衷,不过在这本饭泽耕太郎《写真的思考:摄影的存在意义》里,作者传达了一个容易被忽视的审美角度——有的摄影作品是“以偶然的方式处理偶然,并将其必然化”。这里所说的偶然,毫无疑问指的是摄影行为本身的偶然,而所谓的必然,其实是摄影行为在凝结为摄影作品后,呈现给观众的必然。将「偶然」作为摄影行为的动机,是刻意扰乱意识性的控制、主动地选取错乱的过程。这在摄影创作中并不少见,但我们往往习以为常,而忽略了它作为摄影动机的深刻内涵。</p>
<p>现代主义和现代性的模糊定义,看似并没有给摄影艺术的解构来带多大困难,虽然难以从时间维度描摹摄影现代主义的全貌,但并不难从各种作品的共性中找到蛛丝马迹。作者在这部分提到了「断裂」与「再现」的概念。具体来讲,将客体从远观到近观的局部摄影,将客体从语言层面的所指转向能指的超现实主义摄影,都是一种以「断裂」为形式的创作,而摄影冲印技术的发展,又无不是「再现」的同义反复。现代主义在这样的过程中慢慢褪色,用作者的话来说,「尽管“后现代”这件衣服迅速穿上之后又被脱下,“现代”仍渗透在我们的骨头中、侵蚀着人类的思考与感受」。</p>
<p>从书名出发,「写真」一词的内涵远远超出了我们通常给它的定义——特指人物肖像的摄影类型。恰恰相反,写真的定义是具体而又宽泛的。在摄影技术刚刚进入日本时,人们对这样全新的成像技术抱有极大的好奇,什么是真实?如何描摹真实?这两个问题在很长的时间尺度上陪伴着人类的绘画艺术,而摄影技术的出现,从根本上实现了写实主义,说到底,这恰恰就是一种对真实的写照,也是就作者想要表达的「写真」之意。摄影技术刚刚兴起的时期,也正是祛魅与复魅发展的时期,例如一些摄影师寻找非职业的摆拍者在棚内进行场景再现,利用摄影的写实主义特点进行的创作,不仅满足了受众对「写真」的心理需要,也让写真一词的定义更加深刻,这正是技术祛魅的实证。随着摄影印刷的普及,明信片的大量生产使耗费手工且价格昂贵的写真艺术快速衰退,新的技术浮上水面,为人类社会重新复魅。</p>
<p>摄影作为记录,或者作为创作的特性自然无需多言,更多的或许只是摄影艺术本身如何从这二者中进行选择的问题。不过,「死者的照片」却远远突破了这个论点,表现出具有普遍性的哲学内涵——死者不愿被遗忘,或者说生者不愿遗忘死者的羁绊。在现代社会以前,能够通过绘画艺术将自己的样貌「不朽」的,毕竟只是权贵等少数人。摄影术的出现,大大降低了这个原本只有少数人拥有的「不被遗忘权」。生者与死者通过影像的记录,获得了精神上的接触和联结,而死者真正的死亡,也被长久地延续到了被所有后人遗忘的时间点。遗照的拍摄角度、遗照的保留方式,在不同文化背景下的巨大差异,那又是另外的话题了。死亡作为人类无法回避的哲学命题,也就这样自然而然地通过摄影技术的大众化,传递到了普罗大众的生活中。</p>
<h2 id="读书笔记">读书笔记</h2>
<p>第 21 页<br>
即使是美丽花朵、可爱小猫、美味料理等照片,如果以婴儿般未开化的眼光来重新审视的话,应该仍可窥见各种各样神话性的现象,如漩涡一般翻转着。持续端详之下,照片中的含意将会分支,多层化、流动性地变换和组织,最终产生出意想不到的结合。换句话说,初看普通的照片在深入审视后也有可能完全变为夸张而怪诞的异物。此外,还可能引发出逆转现象,将理所当然的东西转变为特异且独一无二之物,或者将特别的事物变成具有普遍性的东西。</p>
<hr>
<p>第 32 页<br>
十九世纪中叶,摄影技术在世界各地扩展时,曾经被视为一种具有魔力的装置:“被拍照时,灵魂会被抽取而出”。不仅在日本类似这样的流言全世界都在流传,换句话说,也就是会被引领去往死亡的世界。而十九世纪最被人喜爱的摄影领域之一,便是拍摄眼睛所不能见到的灵魂存在的灵异照片,这种喜好的理由多少也包含了摄影会抽取出灵魂的想法。</p>
<p>从十九世纪进入二十世纪后,这样的魔幻性质却随着时代进步而急速消逝。因为器材与底片的进步,大众化的摄影转变为社会沟通的手段,成为仅是正确再现、传达图像的工具。而二十世纪末正式展开的数码摄影,更让我们确认了此一演变方向。时至今日,相机已经成为一种可以控制、容易上手、便于使用的工具。</p>
<hr>
<p>第 42 页<br>
拍摄这件事情既是“射击=杀死”,也是被“击中=复活”。</p>
<hr>
<p>第 57 页<br>
“全体”的解体</p>
<p>让我们暂且先以“断裂”这个名词来表达现代主义摄影的基本原理之一。就如斯蒂格里茨的《乔治亚·欧姬芙》所展现的,即正是这种断裂的典型。贯穿现代摄影的,便是从预先依照秩序安排好的“全体”中取出“断裂”的部分[或从中分离出某些片断],给观看者类似强迫症般的提示,这样的提示可将部分全体化。与眺望构图宽广的画面相反,这样一来反而会带给人一种奇妙的、切实的执著感。</p>
<p>以“特写”来说,这种在现代摄影中频繁出现的技法,是最容易让大家理解的例子。整个现代主义时期大量出现从脸、人体、建筑物、机械类、植物等全体中撷取一部分放大拍摄的题材,亦即全体的部分化,同时也是部分的全体化。这些特征超越了摄影师出身的国籍、经历、个性等,让我们体验到同时代性的感受。</p>
<p>这些摄影师使用特写技法所要追求的,就是将被摄体从日常视觉感受的全体性切割出来,并将其还原到单纯“物”的层面。</p>
<hr>
<p>第 60 页<br>
费尔迪南·索绪尔[Ferdinand de Saussure],将语言当作能指[significant,符号的表征]与所指[signifie,符号的内容]的结合来处理,再各自对应到语言的“概念”与“意义”。根据他的说法,能指与所指的结合是随意的,不需要任何内在的动机或根据,亦即将能指与所指切割开来,让另一个语词“意味的内容”整个更换过去也完全可行。而类似这样能指与所指的再构成,于影像符号上执行比在语言符号上更加彻底,这是因为影像本身并不像语言一般有着严密的符码对应关系,相对来说能指与所指的连接也比较松散。</p>
<p>超现实主义者便利用摄影这种表现媒体,将原本影像上的意义作用因“间隔化”更加扩大。曼·雷或勃法所拍摄“一点都不奇怪”的帽子、汤匙、洋伞、街角景致等,不仅是剥夺了它们现实性的能指,还外加“情色性象征的书写”与其他所指结合。</p>
<hr>
<p>第 66 页<br>
再现与复制,使得影像生产力大增。借由摄影师之手,影像由日常脉络中被切割开来、赋予特别的意义,然后在极短的时间内再度被日常化、陈腐化。位于时代“尖端”的影像在短时间内不断地被消费,进而变得司空见惯且理所当然。为了对抗这种影像消费的空转,现代主义者们只能被迫不断穿上新衣,又不得不迅速地脱掉舍弃。</p>
<p>在历史上,没有其他时期像现代主义时代一般,不停开发各式各样新技法,反复进行技术性实验。而这个时期的摄影师们也必须自发性地频繁改变作品风格,此现象在其他时期也是很罕见的。也因为如此,从现代主义出现以来,“新奇度”便成为评价的绝对基准。</p>
<hr>
<p>第 88 页<br>
对艺术活动而言,让当时摄影师觉得感动且互享的那种欢愉,应该是对被描绘的、被拍摄出来的、与原物品完全一致的那种纯粹与惊奇。但将其推到极端来说,影像究竟是什么,对他们而言并不构成任何问题。与原物品几乎一致但却非原物品,这种类似制作出某种拟造物,有如机械机关一般的复制机制,才是他们深感魅力的所在。这让他们愿意沉迷其中,也是让他们努力于摄影与西洋画的原动力。</p>
<p>那是一种在没有任何干涉与关联下产生出的空虚,也是一种缺乏对象物的“写实”。正是这种状态,才让摄影师的作品展现出奇妙的真实感。</p>
<p>在这样的论点上,他们从事的并非是“艺术家”的工作,而是一种视觉上的娱乐,更接近新奇事物的展示。</p>
<hr>
<p>第 96 页<br>
一百六十多年前,摄影传入日本之际,适逢维系近三百年的江户幕府崩坏,新社会、新文化的框架重新形塑的时期。或许这种动荡不安、持续有重大变化的社会状况,也正好唤醒人们对“真实”的追求意识。此外,这个时期也正是摄影原有的魔幻性、神话性的思考,仍在摄影师与画家们间共通、共有,并以各种形式满地开花的时期。如前所述,明治中后期以后,当日本逐渐转型为现代国家的时期,摄影与绘画一体化的魅力表现,便急速地瓦解。</p>
<hr>
<p>第 103 页<br>
在达盖尔与塔尔博特发明摄影的时代,背后推动与支持他们的文化背景,其实正是该年代对“静物”的欲望与需求。</p>
<p>这个概念可以追溯到十八世纪至十九世纪前半期,支配欧洲人“观看”意识的“如画风格”美学,前文所描述的静物摄影也可以说是反映这种美学的一种产物。如画风格的美学意识后来也影响到十九世纪末形成的“画意摄影”,这部分已经于前文提及在摄影师们努力把照片“艺术化”作为目标的时代,如画风格的绘画便是他们的规范。也是这种根深蒂固的符咒催生了摄影术,并成为摄影以惊人速度发展的契机之一。</p>
<p>简单地说,“如画风格”是将眼前宽广的世界以“边框”围起,当作一幅图画来观赏的意识。如果将这种意识彻底化,就会产生比起现实世界,图画反而让人更感到真实的倒错感。例如高山宏在《目中的剧场》中,描述了流行于十八世纪,一种称为“克劳德镜”[Claude Glass]的奇妙光学器具。这种“直径约四英寸的凸透镜”,可以选择观看者喜好的色调箔片,而透过这个工具观看风景时,可以变换、映照出对现实的凝视,就如同当时深受大众喜好的克劳德·洛兰[Claud Lorrain]的风景画一般。携带着克劳德镜的旅行者,只要将风景框进透镜,便能够随心所欲地享受“如画风格”的美景。以这种方式观赏风景的时代,也代表着观看者的行为“在结构上是和自然相对”的。</p>
<p>在某种意义上,如画风格也是将世界所有可能的影像都缩小,封存入“眼中”的一种意识。诚如多数评论者指出,在摄影术快速发展的十八世纪到十九世纪之间,它将视觉从听觉或触觉等其他感官中独立出来并放大。“观看”与“拥有”被直接联系在一起,以“观看者”为中心,将世界再组织的欲望便从此昂扬前进。</p>
<hr>
<p>第 109 页<br>
然而,在第一次世界大战后的1920年代,不知为何,无生命的拍摄对象又再度复苏,成为摄影的被摄体。</p>
<p>……</p>
<p>这些静物摄影,与上一个世纪受如画风格美学影响而创作的作品有着微妙的差异。举例来说,如画风格美学意识中最重要的,便是以观看者为中心,“如人们想看的一般去看,如想切取一般的去切取”出画面并封存于取景框之中,以及审慎细致地去进行画面配置。但是1920至1930年代以物件为主题的摄影作品,占据主角位置的不再是人类,而是对象本身。对象脱离人的控制而主张自我的存在,可在画面中任意、任性地繁殖,仿佛彼此秘密交谈一般。这种奇妙的氛围是我们观看这些作品时所能察觉到的,所以在这些创作中占据世界中心位置的与其说是人类,不如说是对象。</p>
<p>像这样的逆转,起因应该是将全欧洲逼迫至极限状态的第一次世界大战所带来的对过往以人类为中心的价值观进行反思所产生的危机感。人们过去认为自己与世界的关系是确实而明确的,但在世界大战中,这种想法无可抑制地崩坏。因为异物化的巨大战争机器,让人们的生命无论在何处都暴露在致命的危险之下。这些应该受支配的物品,从人类的桎梏中逃脱并任意地到处漫游,让人觉得它们仿佛正在各处自我增殖。对象不再是能被操作的道具或工具,反之是活生生显露出敌意的异物。</p>
<p>不仅如此,1920至1930年代也是人们眼前陆陆续续、不断出现过往未曾看过之异物的年代。汽车、飞机、地下铁等新的交通工具,钢筋、水泥与玻璃所建造的充满设计感的建筑,泛着黑色光泽与钢铁肌理的机械在撕裂大地的同时又将空间多层次地连接起来,这些机械时代的产物,伴随着对几何学结构美的礼赞,但人们也意识到这些异物已经超越人类的控制范围,成为无法控制
的存在。而摄影师们面对这些不熟悉的物品,内心的憧憬与嫌恶、恍惚与不安、留恋与抵抗等思绪必然产生激烈冲撞。</p>
<hr>
<p>第 120 页<br>
就结果来说,摄影师们憧憬着超越人类思考与感觉尺度的物件本身它们所含有不可思议的力量,以及抱持着能够将其自由操作转化为任何变异影像的欲望,将这些冲动与摄影这个包含了各种矛盾的媒体结合,便形成了上述的静物摄影历程,并让摄影出现在既不是物件也不是影像[反之也可以说既是物件也是影像]的中间性区域。因此,摄影所拍摄下来的物件,一方面保存了物件的真实性,另一方面也保持着物件作为影像可被操弄的矛盾。</p>
<p>静物摄影,在某种意义上可以说截取了摄影神话性、魔幻性思考中最直接的形式。物件与影像的双重性,既互相分裂也相互需要,对于此矛盾性的存在,只要人们还想去追求、厘清这种狂野的谜团,沉迷于静物的摄影师们的历史就会延续下去,不会断绝。</p>
<hr>
<p>第 134 页<br>
三浦雅士在他那充满启发与刺激性的摄影集《幻影般的另一人 现代艺术笔记》[冬树社出版,1982年]中提及,摄影师们虽然身处某处,却同时不具有身处该地的存在意识,也就是将自己定位在“幻影般的另一人”。他们的存在,就像是在不知不觉中混入玩耍的小孩里,计算人数时不管怎么数都会多出一个人来的妖怪——座敷童子。摄影师们“不管在什么状况下都不能够成为相关的当事者。他们经常是从情境中多出来、如幻影般的另外一个人,而除此之外他们什么都不是”。正因为如此,与摄影师们同处于封闭空间中的裸体女性,才能够平心静气地展现身体。而在战场或事故现场中,摄影师们也会自情境中抽脱,如此才能够以自在的,有时候甚至是旁若无人的方式,来进行拍摄。</p>
<p>这种专属于摄影师们的特权地位,便是由纯粹的“观看者”而来。当手中握有魔法般的装置,他们也同时可以将所有人事物转换成“被观看者”。在某种程度上,我们甚至可以说摄影师的凝视已经转化成能扫视一切,绝对的神之视线,能在制高点上看穿所有人们、风景,以及处于其间的复杂脉络。但即便是具备如此全能视线的摄影师,也有一处是他们所观看不到的,那便是这些摄影师自身。</p>
<hr>
<p>第 190 页<br>
直到创造性的快照出现为止,摄影师与被摄体的关系,大致上不是保持远距,就是拉近距离。“家庭快照摄影”的拍摄者与被拍摄者间的关系,不用多加说明也知道是极端亲近的,而这种物理性、情感性的亲密度,便会唤起观看者无法压抑的怀念感受,或者是对逝去过往的唏嘘。反之,人类学者去未开化的部落拍摄,或者纪录悲惨的事故之时,就会与被摄体保持距离,因为他们需要一定的客观性,如果不这么做而投入自己的感情,恐怕就会漏失掉重要的画面。</p>
<p>所以,要如何判断作品是否为优秀快照的秘诀,便在于是否能够尽力保持不远也不近,以不断调整、接近及拉开与被摄体之间的关系。这件事情看起来简单却意外的相当困难。如果与被摄体产生亲近与习惯的感觉,就容易染上主观的色彩,进而卷入说明式的脉络中,最后容易变成刻板印象式的量产作品。反之,如果与被摄体保持相当的距离而致力于调整整体构图,并过度专注于按下快门的时机的话,被摄体又会变成不过是画面构成的素材而已。</p>
<hr>
<p>第 244 页<br>
“主题演讲”中,东松对自己的摄影方法做出如下表述:</p>
<blockquote>
<p>摄影可说是科技中的媒体先驱,而摄影的特征,或者是百分之一秒,或者是十分之一秒,总而言之便是一种瞬间的静止。如果换种说法,也可以说摄影具备了杀死时间的机能。当然将无时无刻不在前进的时间止于一瞬的说法,其实也不过是停住了时间的影子而已。所以,似乎可以说摄影是虚构的,也确实是如此。它切割出一片生命的瞬间,将其置换到被称为照片的平面上,进行永久性保存。如果这世上的所有事情几乎都是以实体存在的,那么,对拍摄黑白照片的人来说,他们就是使用黑白色调将彩色的世界抽象化,然后再进行永久保存。</p>
</blockquote>
<p>这里他所说的将现实世界的时间切割之后再重新组合,其实是非常优秀的“现代主义”摄影观。把流逝的时间以几分之一秒为单位进行切割,并“将其置换到被称为照片的平面上”然后加以保存。这个切割与保存的程序,东松用“杀死时间”这样卓越的比喻来表达。也可以说,时间应该是处于假死状态,并由观看者的“手”加以“解冻”,让“被杀死的时间经由观看者再度苏醒”。</p>
<hr>
<p>第 263 页<br>
葬礼在某种意义上可以说是记忆的祭典。这是一个唤醒来参加典礼的凭吊者们的记忆,让他们每个人都想起往生者在世的模样,而且是每个人都积极参与的魔法仪式。在这个白热化的心灵能量交换场所,摄影的“重生记忆”的力量也被最大限度地激活,即便对像我这种与父亲有点疏离的人来说[话说回来也并没有特意要疏远],看着他生前的姿态慢慢被播放出来,也无法遏抑强烈的哀痛与思念。所以,如果是容易被影响的性格,而且与逝者有着更加深刻联系的人,那就更加容易陷入狂乱的情绪里,这也是可以充分理解的。</p>
<p>在葬礼这种稍微脱出常轨而带有使人情绪激动的空间中,摄影与死者被刻意混合。某种意义上葬礼的主角,反而不是躺在覆盖着花朵的棺木中那位真正的死者[虽然这是有点奇怪的说法],而是祭坛上摆放的遗照。吊唁者凝视着往生者的照片,对着它双手合十祈求冥福,有时对着它呼喊,有时对着它流泪,看着它无法遏制自己情感的人更不在少数。不过这魔法的持续性并不长,当葬礼结束之后,这幅放大的遗照就会被收藏妥当,谁也不会再回头去看它。或许会被暂时放在厅堂挂着,但最终照片还是会被收到某处,或者被秘密处理掉。</p>
<p>人们有时也会将亡者的小照片与牌位一起供奉在佛坛上,但即便如此也会逐渐蒙尘,变成一年一次或两次的仪式性膜拜而已。记忆逐渐稀薄,认识逝者的人,也如梳子的梳齿逐渐脱落一般,一个随着一个消逝,遗照的魔幻性力量也会随之涣散,最后完全还原到只是一幅普通的照片而已。当对持有逝者记忆的人一个也不存在,所有人都将之遗忘掉时,也就是逝者初次成为完全的亡者的时刻。如果不是在艺术或文学上留下作品,也非在政界或商界活跃而留下昭彰恶名者,普通默默无闻的死者,大多都会走上如此的命运。</p>
<hr>
<p>第 272 页<br>
沿着这些照片回溯,我们可以看到从十九世纪到二十世纪初期,对一般的美国人而言,这些“死者的纪念照片”所具有的特别意义。即使他们是以今日我们无法理解的热情去持有死者的肖像,但我们还是可以感受到由于伴随着这样的持有,使他们也对生命更加坚持。伯恩斯针对当时的情况,在摄影集的序文中写道:</p>
<blockquote>
<p>绘画是富裕的名人为了记忆而使用的媒体,该功能从十九世纪以来一直没有改变,而摄影不仅能创造出视觉图像,同时也是能提供给所有人观看的媒介。因此,过往只有富裕阶层才能拥有的不死性,在摄影出现后便为千万人敞开大门。死者的纪念照片,不仅只是单纯唤醒记忆,例如年纪幼小还没拍过照片即过世的人们,纪念照片也可以替他们保持形貌。</p>
</blockquote>
<hr>
<p>第 272 页<br>
让伯恩斯特别关心的,是美国与欧洲“死者的纪念照片”在本质上的不同。观看《睡美人Ⅱ》中刊载的拿破仑三世[E.阿贝尔特拍摄]、维克多·雨果[Victor-Marie Hugo][纳达尔拍摄]、疯王路德维希[LudwingⅡde BAVIERE][F.华纳拍摄]等人在床上过世的照片,即可以理解这些作品都遵从传统图像学,在拍摄时都强调堂堂正正的父性元素。在欧洲,不限于这些君主或者名人,在一般的死者的纪念照片中,对“王权、贵族制度、财力等特权于公开场合表明”的突出表现也很多。</p>
<p>与此相对,在美国就以“个性的丧失感与私人性的表现”为中心。大多数的场合,并不会作夸饰社会地位的演出。此外,美国的死者的纪念照片比较多都是收入盒中或以个人可以带着走的形式放置,而欧洲则会装上画框挂于墙上。美国的死者的纪念照片,较欧洲的酝酿出更多的亲密氛围,可以说是作为“日常生活中极其自然的一部分”来发挥其功能。</p>
<p>这样的差异,当然是由美国与欧洲传统文化的差异所衍生出来的。欧洲的家族比较容易保有国家、民族文化以及历史的羁绊,与这种状况相对,身为移民国家的居民,美国人对自身身份的认同,不得不以家族为单位,所以他们对死者也是家族成员之一的意识,希望能够继续这样保持下去的愿望,比欧洲家族来得更加强烈。而这样的愿望,均会加强想要持有死者的纪念照片的欲望。</p>
<p>他们“为了表明希望借由摄影的魔法来延长与死者的关系,而[在拍摄照片时]与时间立下契约”。</p>
<hr>
<p>以上摘自:</p>
<p><img src="https://i.loli.net/2020/01/21/cRlXZAfeFKOgN3z.jpg" alt="《写真的思考》"><br>
<a href="https://book.douban.com/subject/26292968/">《写真的思考》</a><br>
副标题: 摄影的存在意义<br>
作者: [日]饭泽耕太郎<br>
译者: 黄耀进<br>
出版社: 广西师范大学出版社 <br>
ISBN: 9787549562756</p>
《功利主义》译者序读书笔记
https://acuario.xyz/others/utilitarianism-translation-clip/
2023-09-27T18:25:39+00:00
2019-12-29T19:01:47+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>功利主义作为重要的哲学理论,对近、现代社会、文化以及政治发展产生了不可忽视的影响,了解功利主义的基本意涵和发展脉络,是理解社会文化和大众心理的重要途径。本文系笔者阅读徐大建为约翰·穆勒的《功利主义》一书所作的译者序后,进行文摘和要点整理而作。由于原文较长,纵向分析了功利主义及其他哲学理论源流,也横向对比和列举了其他理论作者提出的对功利主义的批判和质疑,遂整理此文便于复读和思考。本文内容大部分源于对译者徐大建所作序文的摘录,部分排版和要点略有修改。</p>……
<p>功利主义作为重要的哲学理论,对近、现代社会、文化以及政治发展产生了不可忽视的影响,了解功利主义的基本意涵和发展脉络,是理解社会文化和大众心理的重要途径。本文系笔者阅读徐大建为约翰·穆勒的《功利主义》一书所作的译者序后,进行文摘和要点整理而作。由于原文较长,纵向分析了功利主义及其他哲学理论源流,也横向对比和列举了其他理论作者提出的对功利主义的批判和质疑,遂整理此文便于复读和思考。本文内容大部分源于对译者徐大建所作序文的摘录,部分排版和要点略有修改。</p>
<hr>
<h2 id="西方社会思潮及功利主义理论纵览">西方社会思潮及功利主义理论纵览</h2>
<ul>
<li>
<p>现代西方社会思潮的主流是自由主义内部分为三大派别:</p>
<ul>
<li>自由平等主义</li>
<li>自由至上主义</li>
<li>功利主义</li>
</ul>
</li>
<li>
<p>从方法论的角度说,最有影响的西方社会思想流派:</p>
<ul>
<li>契约论学派:发源于古代自然法学派</li>
<li>功利主义学派</li>
</ul>
</li>
<li>
<p>当代自由主义契约论学派的基本观点:合乎道德的行为或制度应当符合正义的原则。所谓正义,简要地说就是尊重或者不侵犯个人的基本人权。因为人的理性都是相同的,所以我们可以诉诸每个人的同意,而诉诸人们的一致同意差不多也就相当于诉诸人的理性。</p>
</li>
<li>
<p>在古代西方的自然法学派的论证:人类行为规则的根据来自上帝颁布的自然法,由天启理性得到;尽管现有的许多行为规则属于人类法,是人制定的,但它们的最终依据是自然法,是自然法根据具体现实情况的某种应用这样的论证不免使得被自然法认可的一切都带有某种神秘性乃至神圣性。</p>
</li>
<li>
<p>近现代功利主义认识论的基础:一切知识的取舍最后都要诉诸人的日常经验而不是诉诸人的理性或上帝,伦理道德的论证也不例外。</p>
</li>
<li>
<p>休谟(David Hume,1711-1776)的怀疑论对自然法学派进行批判,人为自然法学派的“理性”包含着三种不同的含义:</p>
<ul>
<li>对观念之间必然联系的认知,它与经验无关,所以具有绝对真的性质,但这种性质仅存在于逻辑和数学这样的同义反复的命题之中;</li>
<li>对事物的经验性因果关系的认识,但这种因果关系并不存在必然性而仅仅是心理习惯而已;</li>
<li>对正确的人类行为规则——特别是诸如权利、正义或自由之类的理性原则的把握,但这些所谓的理性原则其实不过反映了人们的趣味或情感而并非理性的东西所以,自然法学派所宣称的出于理性的自然法原则,其实不过是由经验根据其是否有利于社会稳定和公众利益的结果判断为正当的行为标准,实质上是人类情感、心理习惯和社会习俗的混合物,而非出自自然的永恒真理。</li>
</ul>
</li>
<li>
<p>亚当·斯密(Adam Smith,1723-1790)从政治经济学的角度发扬了功利主义的精神。斯密的基本理论可以归纳为三个要点:</p>
<ul>
<li>人的全部行为基础是一种双重性的天赋人性人人都同时具有自利心和同情心;</li>
<li>经济行为的目的应当是个人的自由自主的幸福生活及其必要条件国民财富的增长或社会财富最大化;</li>
<li>第三,在这样的人性基础上,为了达到社会财富最大化的目的,基本的途径应当是基于市场经济的自由放任的经济政策以及严格保护财产权利和契约义务的政治制度。</li>
</ul>
</li>
<li>
<p>亚当·斯密的功利主义精神表现在:</p>
<ul>
<li>他用经济学的语言“国民财富最大化”解释了“最大多数人的最大幸福”这一功利主义的终极目的;</li>
<li>他说明了如何在自利的人性基础上达到功利主义目的的根本途径,即通过公平竞争来获得效率的市场经济体制,从而为经济学奠定了功利主义的伦理框架。</li>
</ul>
</li>
<li>
<p>边沁(Jeremy Bentham,17481832)首次对近现代功利主义作了一个比较全面的阐述。边沁认为,感觉经验是包括道德知识在内的一切知识的最根本而又真实的基础,因此,伦理道德也不能不建立在为人类经验所认可的人的趋乐避苦的本性和自我利益的追求之基础上:“当我们对任何一种行为予以赞成或不赞成的时候,我们是看该行为是增多还是减少当事者的幸福。”当每个人都真正得到了自己的最大利益时,社会也就达到了“最大多数人的最大幸福”,为“最大幸福原理”依赖于每个人的最大幸福之加总。于是,功利主义道德基本上就在于苦乐的计算。</p>
</li>
<li>
<p>在边沁的理论中,开明利已主义与功利主义是一致的。</p>
</li>
</ul>
<h2 id="穆勒功利主义概览">穆勒《功利主义》概览</h2>
<h3 id="功利主义的含义">功利主义的含义</h3>
<blockquote>
<p>把“功利”或“最大幸福原理”当作道德基础的信条主张,行为的对错,与它们增进幸福或造成不幸的倾向成正比。所谓幸福,是指快乐和免除痛苦;所谓不幸,是指痛苦和丧失快乐。……唯有快乐和免除痛苦是值得欲求的目的,所有值得欲求的东西(它们在功利主义理论中与在其他任何理论中样为数众多)之所以值得欲求,或者是因为内在于它们之中的快乐,或者是因为它们是增进快乐避免痛苦的手段。</p>
</blockquote>
<ul>
<li>前半部分是对道德规范问题的回答:判定行为对错的唯一最终道德标准是看行为是否能够增进人的幸福或快乐。</li>
<li>后半部分则是对人生意义问题的回答:增进快乐和避免痛苦是人生的唯一终极价值或“善”,其他任何值得欲求的东西或“善”都是为了增进快乐和避免痛苦。</li>
<li>后者是对前者的目的的说明,是前者的基础。</li>
<li>穆勒认为,伦理学的全部问题都可以归结为穆尔所说的:
<ul>
<li>所论的对象具有本然价值吗?</li>
<li>所论的行为是达致最好可能结果的手段吗?</li>
</ul>
</li>
</ul>
<h3 id="幸福或快乐的定义">“幸福”或“快乐”的定义</h3>
<ul>
<li>边沁的功利主义有两个特点:
<ul>
<li>幸福或快乐是同质的因此可以在人际间进行比较和加总</li>
<li>功利主义的基础是人的趋乐避苦的本性和利己主义理论</li>
</ul>
</li>
<li>穆勒认为,功利主义所谓的“幸福”或“快乐”不是指动物的幸福或快乐,而是指人的幸福或快乐。承认某些种类的快乐比其他种类的快乐更值得欲求更有价值,在评估事物时,不论客体为何物,都考量其质量与数量。</li>
<li>穆勒认为,功利主义并不反对自我牺牲,但反对把自我牺牲本身看作善事:“一种牺牲如果没有增进或不会增进幸福的总量,那么就是浪费。它唯一赞成的自我牺牲,是为了他人的幸福或有利于他人幸福的某些手段而做出的牺牲。”</li>
<li>穆勒认为,功利主义与传统道德之间的关系是:</li>
</ul>
<blockquote>
<p>功利主义要求,行为者在他自己的幸福与他人的幸福之间,应当像一个公正无私的仁慈的旁观者那样,做到严格的不偏不倚。</p>
</blockquote>
<h3 id="功利主义道德标准">功利主义道德标准</h3>
<ul>
<li>功利主义道德标准的外在约束力:“希望从自己的同胞和宇宙的主宰那里得到恩宠,不愿在自己的同胞和宇宙的主宰那里找不痛快,以及我们对同胞的同情挚爱和对宇宙主宰的敬畏等等”</li>
<li>功利主义道德标准的内在约束力:被我们称之为“良心”的道德感情,这种道德感情是在与同胞和谐一致的愿望这种天赋社会感情的基础上通过教育培养起来的。功利主义道德完全是符合人性的,是不难为人遵循的。</li>
<li>穆勒认为,功利主义道德标准的证明过程有一下几个要点:
<ul>
<li>证明过程要么根据原理的推理,要么是诉诸事实的。但功利主义原理只能诉诸事实。</li>
<li>据此,需要证明事实上人生应当追求的最终目的是“最大多数人的最大幸福”。</li>
<li>据此,需要证明每一个人或至少是大多数人事实上追求“最大多数人的最大幸福”。</li>
</ul>
</li>
<li>穆勒认为,“每个人都在相信幸福能够获得的范围内欲求自己的幸福”是一个事实,所以“我们就不仅有了合适的证据,而且有了可能需要的一切证据来证明,幸福是一种善:即每个人的幸福对他本人来说都是一种善,因而公众幸福就是对所有的人的集体而言的善。”。此处「从每个人都追求自己的幸福直接推出每个人都追求最大多数人的最大幸福」缺乏论证。</li>
</ul>
<h3 id="功利主义理论与正义的关系问题">功利主义理论与正义的关系问题</h3>
<h4 id="正义是什么">正义是什么</h4>
<ul>
<li>穆勒认为,正义这个观念含有两种要素:
<ul>
<li>行为规则</li>
<li>赞同行为规则的情感,即正义感</li>
</ul>
</li>
<li>正义的行为规则有五种公认的正义规范:
<ul>
<li>尊重或不侵犯个人的法定的权利</li>
<li>尊重或不侵犯个人的道德的权利</li>
<li>尊重或不侵犯个人的应得的权利</li>
<li>尊重或不侵犯个人的约定的权利</li>
<li>尊重或不侵犯个人的天赋的权利</li>
</ul>
</li>
<li>正义规范包含着人的权利:“任何情况,只要存在着权利问题,便属于正义的问题,而不属于仁慈之类的美德的问题”换言之,一般人所谓的正义规范,就是尊重或不侵犯他人的正当权利。</li>
<li>穆勒认为,正义感含有两个本质要素:
<ul>
<li>相信存在着某个或某些确定的权利受到侵犯的受害者</li>
<li>想要惩罚侵害者——此要素催生自卫冲动和同情</li>
</ul>
</li>
<li>正义观念归结为两个要素:
<ul>
<li>对权利的侵犯</li>
<li>对侵害的惩罚,或对权利的保护</li>
</ul>
</li>
</ul>
<h4 id="正义与功利的关系">正义与功利的关系</h4>
<ul>
<li>正义是建立在权利或利益的基础上的,是对正当权利或利益的维护。</li>
<li>正义是对权利的尊重,那就意味着社会对权利的保护。我们需要正义和对权利的保护,是因为这涉及到我们的最为至关重要的利益,即安全利益:</li>
</ul>
<blockquote>
<p>对人类的福利来说,禁止人类相互伤害的道德规则最为至关重要……因为一个人很可能并不需要别人的恩惠,但却始终需要别人不伤害自己。所以唯有那些保护每个人免受他人伤害——不论是他人的直接伤害,还是由于追求自己幸福的自由受到阻碍而遭到的伤害一的道德,才会立即成为每个人本人最为关心的东西,成为每个人最有兴趣用自己的言行努力宣传和贯彻的东西。</p>
</blockquote>
<ul>
<li>不同的人 / 同一个人在不同的场合对公平正义有不同的看法。解决争论的依据只有功利主义原则。</li>
<li>综上,穆勒认为,正义不是一种底线道德,而是保证人与人互不侵害的必须原则。但由于没有统一的正义标准,故在不同的正义标准发生冲突时,取舍的标准唯有社会功利。因此,正义建基于功利之上。</li>
</ul>
<h2 id="穆勒的功利主义理论缺陷">穆勒的功利主义理论缺陷</h2>
<ul>
<li>西季威克(Henry Sidgwick,1838-1900)认为,穆勒虽然强调的是“最大多数人的最大幸福”而不是任何一个个人的幸福,但他却是从每一个人事实上追求自己的幸福出发来推出每一个人应当追求“最大多数人的最大幸福”的,此推理至少需要克服两个环节:
<ul>
<li>从实际被欲求的东西推不出值得欲求的东西</li>
<li>从个人实际上追求自己的幸福推不出个人实际上追求公众幸福</li>
</ul>
</li>
<li>西季威克认为,要从个人实际上追求自己的幸福推不出个人实际上追求公众幸福,必须加上“合理仁爱”而不能仅仅靠“自利”。这也便将功利主义与利己主义彻底区分开来(在边沁的理论中,开明利已主义与功利主义是一致的)。</li>
<li>穆尔(G. E. Moore,1873-1958)对穆勒的功利主义证明进行了猛烈的抨击:穆勒混淆了“值得欲求的”与“实际上被欲求的”,用“实际上被欲求的”来定义“善”,试图用一种自然属性来给一种不可分析不可定义的属性进行定义,犯了一种自然主义谬误。</li>
<li>当代自由主义契约论学派主要代表人物罗尔斯的著作《正义论》旨在构造一个能与功利主义抗衡的作为政治哲学和法哲学的基础的伦理体系。他对功利主义进行批判大致集中在功利主义不能说明正义这一点上:
<ul>
<li>功利主义是把合理利主义运用到社会的结果,因此强调“不偏不倚的旁观者( spectator)的地位和同情”,“并不在人与人之间作出严格的区分”。</li>
<li>功利主义属于目的论,用“善”来定义“正当”,正义作为增加“善”的手段而不关心“满足的总量怎样在个人之间进行分配”,而根据功利主义原则,则无法说明分配公平的问题。</li>
</ul>
</li>
<li>功利主义不承认个人具有神圣不可侵犯的自然权利,功利主义原则会导致为了多数人的利益侵害少数人的合法权益,一方面要求超出自然义务的“自我牺牲的”善行,另一方面给已经更幸运的人更大幸福而牺牲一部分人的福利和自由。</li>
<li>阿马蒂亚·森认为传统福利经济学的目的是追求功利主义的社会福利最大化:
<ul>
<li>后果主义</li>
<li>福利主义,即用效用或快乐来解释福利</li>
<li>把社会福利解释为个人福利的加总</li>
</ul>
</li>
<li>阿马蒂亚·森认为传统功利主义有重视结果、重视福利的优点,但其以效用的总和作为社会成就的判断准则会导致:
<ul>
<li>忽视基本权利等非效用因素</li>
<li>以主观的心理感受来解释效用,忽视了与效用同样重要的主观能动方面(agency aspect)</li>
<li>忽视了分配公平</li>
</ul>
</li>
</ul>
《永久檔案》读书笔记
https://acuario.xyz/others/permanent-record-clip/
2023-09-27T18:25:39+00:00
2019-11-27T23:07:52+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>深入鳳梨田底下的一條坑道——珍珠港時代的一座舊地下飛機廠——我坐在終端機前,可以幾近無限地取得世界上幾乎所有男女老幼的通訊,只要人們曾經撥打過一通電話或碰觸過一部電腦。這些人當中,包括三億二千萬美國同胞,他們日常生活的一舉一動都遭到監視,不僅嚴重違反美國憲法,更是違背自由社會的基本價值。</p>
<hr>
<p>人生是什麼?不只是我們說了些什麼,甚至不只是做了些什麼。人生亦在於我們所喜愛的、所相信的。以我而言,我最喜愛和相信的,是連結,人際的連結,以及促成這些的科技。當然,這些科技也包括書籍。但在我這個世代,連結,主要意味著網際網路。</p>
<p>在你產生反感、明白網際網路瘋狂毒害我們這個時代之前,請諒解,對我來說,當我認識網際網路之時,那是很不一樣的東西。網路既是朋友,也是父母,是一個無邊界、無限制的社群,既是單一、也是無數的聲音,一個已經有人墾殖但尚未遭到剝削的共同邊境,各式各樣的部落和睦相處,每個成員都能自由選擇自己的姓名、歷史和風俗習慣。每個人都戴著面具,然而這種多數匿名造就的文化所產生的事實多於造假,因為重點在於創造與合作,而不是商業與競爭。當然這之間也會有衝突,但善意與善念會勝過衝突——而這正是真正的先驅精神。</p>……
<p>深入鳳梨田底下的一條坑道——珍珠港時代的一座舊地下飛機廠——我坐在終端機前,可以幾近無限地取得世界上幾乎所有男女老幼的通訊,只要人們曾經撥打過一通電話或碰觸過一部電腦。這些人當中,包括三億二千萬美國同胞,他們日常生活的一舉一動都遭到監視,不僅嚴重違反美國憲法,更是違背自由社會的基本價值。</p>
<hr>
<p>人生是什麼?不只是我們說了些什麼,甚至不只是做了些什麼。人生亦在於我們所喜愛的、所相信的。以我而言,我最喜愛和相信的,是連結,人際的連結,以及促成這些的科技。當然,這些科技也包括書籍。但在我這個世代,連結,主要意味著網際網路。</p>
<p>在你產生反感、明白網際網路瘋狂毒害我們這個時代之前,請諒解,對我來說,當我認識網際網路之時,那是很不一樣的東西。網路既是朋友,也是父母,是一個無邊界、無限制的社群,既是單一、也是無數的聲音,一個已經有人墾殖但尚未遭到剝削的共同邊境,各式各樣的部落和睦相處,每個成員都能自由選擇自己的姓名、歷史和風俗習慣。每個人都戴著面具,然而這種多數匿名造就的文化所產生的事實多於造假,因為重點在於創造與合作,而不是商業與競爭。當然這之間也會有衝突,但善意與善念會勝過衝突——而這正是真正的先驅精神。</p>
<hr>
<p>往線上發展電子商務的早期浪潮很快便成為泡沫,接著在本世紀之初終於破滅。在那之後,企業界明白,人們在線上的興趣不在於消費,更在於分享,而且網路促成的人際連結是可以賣錢的。如果人們在線上想做的事主要是跟家人、朋友和陌生人報告自己的近況,從而得知家人、朋友和陌生人的近況,那麼企業只需要設法將自己擠進這些社交互動之中,再從中獲利即可。</p>
<p>這便是監視資本主義(surveillance capitalism)的開端,也是我原先所認知的網路的終點。</p>
<hr>
<p>美國政府在全然漠視開國憲章之下,屈服於這種誘惑,而且一旦嚐過這棵毒樹的果實,便陷入狂熱無法自拔。在暗地裡,政府掌握全民監視的權力,這種權威就定義上而言,對無辜者的傷害遠大於對犯罪者的傷害。</p>
<hr>
<p>隨著千禧到來,網路世界變得越來越中心化、集中化,政府與商業力量加速介入這個原本應是對等式的網路(P2P)。但幸好網路有段時期是由人民所擁有、管理並為其服務的,而這段短暫而美好的日子恰巧與我的青少年歲月重疊。網路的目的應該是啟發人心,而不是追求賺錢。它的規則應由大家約定俗成且隨時更動,而非採取全球一致、剝削性十足的服務性協議。一直到今日,我都認為一九九〇年代網路是我經歷過最愉悅、最成功的無政府狀態。</p>
<hr>
<p>在一九九〇年代,政府與企業的髒手還未伸進網路裡。這兩大力量後來竭盡所能連結使用者的網路身分與真實姓名。孩童過去能在網路大放厥詞、不必擔心後果。這或許不是成長的最佳環境,但網路卻提供你得以長大的唯一前提。我的意思是:網路早期的匿名性鼓勵了我這一代人改變成見,而非故步自封、頑固不化。擁有這種反省的能力,能讓我們傾聽自己內心而不必選邊站,也不須擔心名譽受損而盲從他人意見。錯誤迅速遭懲處然後盡快修正,讓社會與「犯錯者」都能繼續往前走。對我而言(以及許多人),這就是自由。</p>
<p>想像一下,若你想要的話,每天起床都能換張新面孔、選擇新身分,或是轉換新聲音、替換新詞彙。只要點擊「上網按鈕」,你的人生便能重啟。但在千禧年過後,網路科技變得非常不同:所有記憶必須忠實、身分維持一致,意識形態也得正確。但在那時(至少維持一陣子)網路容許我們越界、犯錯的空間。</p>
<hr>
<p>駭客並非僅限於電腦領域,只要規則存在的地方就會有駭客。想駭入一個系統,你必須比系統創造者或經營者更了解規則,並利用這群人預設系統運作與實際運作間的差異。駭客懂得善用這些無心瑕疵,與其說他們打破規則,不如說他們協助暴露系統缺點。</p>
<hr>
<p>我媽早已重返單身戰場,父親則盡力填補內心空虛,但他偶爾還是會因冗長、昂貴的離婚程序而大發雷霆。當這樣的情況發生時,我和父親的角色便會對調,我必須堅定果決地和他講道理。</p>
<p>寫下這段文字令人感到痛苦,原因並不在於重溫過去傷痛,而是這無法顯示我父母本質上的良善。出於對孩子的愛,他們兩人最終化解歧異、和解收場,各自過著幸福的日子。</p>
<p>這樣的改變是恆常、普遍且充滿人性的。但自傳是靜態的,無法記錄下一個人的全部變化。因此,最棒的自傳不是發表一段聲明,而是許下一個承諾,期許自己堅守原則、變成更棒的自己。</p>
<hr>
<p>一般來說,安全許可由低至高分三個層級,依序為信任(Confidential)、機密(Secret) 及最高機密(Top Secret,TS),最高機密等級還可進一步延伸,看符不符合敏感隔離資訊(Sensitive Compartmented Information,SCI)資格。任職中央情報局、國家安全局之類的頂級情治機構,就需要取得TS / SCI這等令人夢寐以求的權限。取得TS / SCI權限的難度最高,但開放的管道也最多,所以我重返母校安妮阿倫德爾社區學院進修,同時在找有利我申請單一範疇背景調查(Single Scope Background Investigation,SSBI)的工作,身家調查涵蓋SSBI這一項。TS / SCI核准程序會耗時一年以上……</p>
<hr>
<p>種種背景檢查的目的,不僅僅是要挖掘我過去幹過什麼勾當,還要查明我會被威逼利誘到什麼程度。對美國情報體系來說最要緊的,不在確認你是否百分之百清清白白,若真在意這點,一個人都僱不到。重點在於你是否誠實無欺,對自己見不得人的祕密坦承不諱,以免被敵方勢力利用來打擊你個人與組織機構。</p>
<hr>
<p>讓我的貼文從地球表面消失不犯法,而且萬一有心人想去挖,我也不用冒著身家調查不合格的風險。不過刪除貼文的可能後果讓我心煩意亂,那麼做只會徒然強化網路生活一些最腐蝕人心的訓誡:沒人有犯錯空間、凡是犯錯者得一輩子為自己的錯誤負責。我在意的倒不是文字記錄是否完美無缺,而是靈魂的完整性。我不想活在一個人人必須假裝完美的世界,那樣的世界沒有我和朋友的容身之處。抹掉在網上的評論,等於抹煞我是誰、我從哪裡來、我走了多遠。否定年少時候的我,等於否定現在的我的合法性。</p>
<hr>
<p>透過電腦螢幕就能脫口而出的事,一旦面對面卻最難說出口。距離反讓彼此更親密,人只有在一個空間獨處,或是與素未謀面的人在各自的空間對話,最能暢所欲言。然而一旦兩人見面,你會覺得綁手綁腳,說話變得保守乏味,徒然只是站在中立立場的尋常對話。</p>
<hr>
<p>與大多數年輕人一樣,我堅信我拒絕認同的信條,本來就不是我的,是從別人那兒承襲來的,而且充滿矛盾。我成長過程中被灌輸的價值,我在網路世界邂逅的理想,全都搗碎在一起成了我現在的思想。我直到即將邁入三十歲之際才終於明白,我所信仰的,我以為自己深信不疑的,大多是年輕時候的印記。我們學說話,是從模仿身邊大人的言談做起,在學習過程中我們也仿照他們的觀念,然後哄騙自己相信,我們的用字遣詞是出於自身。</p>
<hr>
<p>網路文化重大的創始檔案,幾乎都是用會聯想到美國歷史的術語來架構,這裡是有待開發的廣闊新天地,夠大膽的人都能在此安身立命,不過很快會被政府與利益團體殖民,他們為了權與錢會伸出控制魔掌。大企業為他們提供的硬體、軟體、長途電話服務索取高額費用,你想上網就需要它們。連知識這種人類共同遺產,大企業都不放過,照理說知識人人有權取得。英國以宗主國之姿對北美十三殖民地抽重稅,點燃美國獨立火苗,那些獅子大開口的大企業,宛如殖民時期英國的現代化身。</p>
<hr>
<p>我得不好意思的承認,當我經過這群沮喪的員工旁邊時,我是感到多麼驕傲。我比這些服務櫃台的工作人員年輕數十歲,並且握有進入他們以前未曾、未來也不會接觸的保險庫權利。那時候我並不知道這項特權,意味著該過程可能已經出現了問題,政府只是放棄有意義的管理制度,也不再從內部拔擢人才,新的包商文化崛起,反應出他們不重視的心態。在我職業生涯中,我最深刻的回憶在於,經過服務櫃台的這條通道,顯然已成為情報體系在世代與文化改變的表徵。這些舊世代菁英,艱苦的想要趕上他們懶得了解的科技時代,因此歡迎新世代的年輕駭客進入這項組織化的體系,並讓他們對這個由國家控制的空前科技系統進行開發、全面存取、並發揮完全的權力。</p>
<hr>
<p>在中情局上網,必須在同意監看協議的對話方框中打勾,基本上是指你做的每件事都會被紀錄,而且同意不會有任何隱私。由於常勾選該方框,到最後它已成為第二天性。這些協議在工作時多被視若無睹,因為它們經常在螢幕上跳出,你只想把它們消除,重新回到工作上。這是為何多數美國情報體系員工無法感受民眾在網路上被追蹤的不安,並非他們對協助保護美國的數位監督有任何內幕消息,而是在美國情報體系,被老闆追蹤是工作的一部分。</p>
<p>無論如何,這不是說在公眾網路找到的東西比中情局內部的更有趣。沒有多少人知道中情局有自己的網路與資訊網,有自己版本的臉書,讓情治人員可進行社交,也有自己的維基百科,提供團隊、計畫與任務的相關資訊,以及自己的谷歌,實際上由谷歌所提供,讓情治人員可搜尋機密網路。每個中情局部門都在這個網路上有專屬網址,討論他們的工作與貼上會議記錄和簡報。我每晚都要研讀連續好幾個小時,這成為我的教材。</p>
<p>根據法蘭克的說法,每個人在中情局內部網路尋找的第一件事就是外星人與九一一,他說,你永遠無法找到有意義的結果,不過我還是搜尋了。中情局版的谷歌並沒有出現任何有趣的東西,但也許真相在另一個網路上。就我所知的紀錄,外星人從未接觸地球,或至少它們沒與美國情報體系聯絡。不過蓋達組織仍與我們的盟國沙烏地阿拉伯有著密切關係,這是當我們與其他兩國交戰時,布希政府企圖隱藏的事實。</p>
<hr>
<p>我是基礎通訊訓練課程BTTP6-06班的一員。徽章刻意選棕黃色,其實是要偽裝現今所存最機密與罕見的課程之一。該課程的目標在於訓練TISO(技術資訊安全人員),是中情局菁英通訊員的核心,如果用較不正式的話來說,就是「通訊員」。他們被訓練成無所不能,足可取代過去的密碼員、無線電人員、電力人員、技師、物理與數位安全顧問,還有電腦技術師的角色。這個臥底人員的主要任務,是管理中情局營運的技術基礎設施,在海外多數工作站隱藏在美國外交駐所、領事館與大使館等,是美國國務院的附屬機構。會有這樣的構想是因為,如果在美國大使館,不僅遠離祖國,還被令人無法信任的外國人包圍,無論是敵人或盟友,他們對中情局而言仍是無法信賴的外人,那就需要自己人來負責所有技術需求。如果為了便宜行事,找當地的修理工人來維修祕密間諜基地,他們當然會接下這份工作,不過也可能應外國政府要求,在機器內裝設難以追蹤的竊取裝置。</p>
<p>因此技術資訊安全人員是負責修理在建築物內的每台機器,從個人電腦、電腦網路至CCTV與HVAC系統、太陽面板、空調系統、緊急發電機、衛星連接、軍事加密設備、警報器、鎖與其他東西等等。它的規定是如果有插頭或插座,它就是技術資訊安全人員的問題。</p>
<p>這些人也必須知道如何建立系統本身,就像他們必須知道如何摧毀它們。當大使館受到襲擊,所有外交人員與中情局人員都已撤離,技術資訊安全人員通常是最後離開的人。他們破壞、燒毀、清除中情局所留下的痕跡,不論是保險箱的文件或放有暗號文件的桌子,他們要確保剩下的東西對敵人沒有利用價值,之後再傳送最後的「離開」信號給總部。</p>
<hr>
<p>那晚天黑後我待在基地,之後開著我的車到山丘高處,把它停在目前已成為穀倉的地方,我們曾在此學習避免敵人監督我們活動的電子相關概念。當時我們學到的方法跟巫毒很像,都是可以將顯示在電腦螢幕上的內容再次重現的能力,只透過內部元件的震盪電流所產生的微弱電磁發射,利用特別的天線接受這些訊號,這種方法稱為范.埃克(Van Eck)竊聽。如果這聽起來難以理解,我必需承認我們也有一樣的感受。指導員聲稱他從未完全了解技術的細節,也無法為我們展示,不過他知道威脅是真的。中情局對其他人進行這項竊聽技術,意味著後者也將如法炮製。</p>
<hr>
<p>在網路時代來臨前,如果要存取目標電腦,中情局必須招攬擁有觸及目標的實體途徑的線民。這顯然是危險的建議。因為線民可能在下載情報,或是植入將情報傳送給操作者的軟硬體時遭到逮捕。數位科技在全球的擴散已經大幅簡化該過程。這是「數位網路情報」或「電腦網路操作」的新世界,意味著實體管道已不再需要,降低人類的風險程度,並使人員情報與通訊情報能長久獲得平衡。情報員目前只要傳送訊息,例如將附有惡意程式的電郵傳給目標,中情局不僅可監督目標電腦,還包括整個網路。在如此創新下,人員情報將專注於鎖定對象,通訊情報則負責其它工作。如果賄賂失敗,專案人員不用再透過現金、誘騙或勒索來攏絡線民,只要幾次機靈的駭入電腦,也可得到類似結果。更甚者,目標仍然不知不覺。</p>
<hr>
<p>正常而言,當你上網,對任何網站的搜尋,多少會直接連到擁有最終目標的伺服器。還好有被稱為來源與目標標頭的識別碼,每一次搜尋,都會昭告網路過去與未來的足跡。可以把這些標頭想像成明信片的地址。因為它們,讓網站管理員與海外情報體系更容易辨識使用者的網路瀏覽。</p>
<hr>
<p>坐在椅上討論如何駭入沒有面孔的聯合國建築物,在心理上容易得多。情報的技術方面不會有這麼多令人心力交瘁的直接接觸,更遑論電腦運算。螢幕距離造就了去個人化的經驗。從窗戶偷窺別人的生活,可以讓我們對自己的行動不那麼在意,減少結果帶來的重大衝突。</p>
<hr>
<p>住在日內瓦就像住在平行、或甚至是相反的世界。當世界其他地區愈來愈窮時,日內瓦卻更為繁盛。瑞士銀行雖然並無涉及會導致崩毀的高風險交易,但他們卻很樂意藏匿從別人痛苦中獲利的金錢,而且不用為此負責。二〇〇八年金融海嘯,為十年後席捲至歐洲與美國的民粹危機埋下禍根,也讓我了解到,對大眾造成損害的事通常有利於菁英。美國政府在之後幾年,一再讓我更加確認這個教訓。</p>
<hr>
<p>刪除重複數據加上儲存技術優化,使得國安局能儲存情資的時間不斷增加。在我任職期間,國安局設定儲存時間的目標,從收集情資後的數天、數週、數月,一直拉長至五年甚至更久。在這本書出版時,該局能儲存情資的時間或許已達數十年。國安局的邏輯是,收集來的情資一定得儲存起來,日後才能方便運用。但沒人能預測這些情資何時能派上用場。這樣的觀念助長國安局的終極目標,那就是將收集、製造的情資永遠儲存下來,創造出一個完美的記憶庫、一份永久的紀錄檔案。</p>
<hr>
<p>所有人都知道(或自以為知道),中國政府管制網路無所不用其極。而有些人知道(或自以為知道),美國監控能力無比巨大,這是我二〇一三年交給記者的文件披露的內容。但請注意,我們可以用科幻小說反烏托邦的口吻說,政府理論上是可以監聽、監看全民的。但政府想實施這樣的制度卻是另一回事。科幻作家筆下的監控世界,在現實中需要動用數千名技術人員與數百萬美元設備才能辦到。當我讀到中國實施監控的技術細節時,文件鉅細靡遺地描述到:政府動用無數設備與機制監控超過十億人民,每日收集、儲存與分析他們數十億通電話與網路通訊,這實在令我大開眼界。我對於這個監控系統的能力與企圖印象深刻,差點忘記這代表的是極權控制的可怕。</p>
<p>畢竟,中國是個反對民主、一黨獨大的國家。比起美國多數民眾,國安局探員更相信中國是獨裁政體。中國人民的自由並非我的職責,我也無能為力。我唯一可以確定的是,我為好人工作,而這代表我也是好人。</p>
<p>但我讀到的部分資料令我感到不安。我想起科技進展的基本道理:若可以做到某事,那代表未來可以做到,而之前也可能早就做了。美國能夠掌握如此多中國亂搞的證據,代表美國可能也在做同樣的事。我有種奇怪的直覺,當我讀著關於中國的機密資料時,我看到的是美國的倒影。換句話說,中國光明正大對人民做的監控行徑,美國可能背地裡也對其他國家這麼做。</p>
<p>雖然說出這件事你可能會恨我,但我必須承認,我當時壓抑內心不安,甚至賣力忽視此事。我告訴自己,中國與美國的差別是很大的,中國防火長城針對國民進行審查與壓制,隔絕人民接觸到海外資訊,而美國監控系統完全是防禦取向,一般民眾根本察覺不到。就我當時對於美國監控狀況的了解,全世界的人都能透過美國網路基礎建設上網,隨意取得他們想要的資訊,中間未經過濾、沒有限制(就算有的話,也是被他們自己國家與美國企業所隔絕,但這並非美國政府管轄範圍)。只有那些有意參與聖戰士攻擊與購買惡意軟體的人,才會遭到追蹤與監控。</p>
<p>用這個角度來理解,我便能欣然接受美國實施監控。事實上,美國本來就該如此做。我完全支持防禦性、針對特定目標的監控行為,這就像是設立一道有條件的隔絕「防火牆」。這樣的想法讓我的罪惡感一掃而空。</p>
<p>但我後來輾轉失眠,糾纏在心中的問題縈繞不去。在上台簡報過了好一陣子後,我忍不住開始追查更多資料。</p>
<hr>
<p>事實上,偏差定義在整份報告隨處可見,但最離譜的地方莫過於政府更改詞彙意涵。自從PSP於二〇〇一年推動後,恆星風便開始收集通訊記錄,但司法部二〇〇四年抗拒配合,當時小布希政府便更改「取得」(acquire)與「獲得」(obtain)的詞彙定義,試圖讓此計畫過去行徑就地合法。據報告顯示,政府立場是國安局能夠收集他們想要的任何通訊紀錄而不必事先取得搜查令,因為從法律角度來看,只有在國安局從資料庫「搜尋並取得」記錄時,才算是真正的「取得」或「獲得」。</p>
<p>政府大玩文字遊戲,令我十分火大。因為我非常清楚,國安局希望盡可能收集更多資料並將資料留存時間拉長,最好是保存永久。若這些通訊紀錄僅有使用時才算是「取得」,而永久留存在資料庫算是「未取得」,那這些記錄未來便有被操控的空間。美國政府重新詮釋「取得」與「獲得」的定義,從原本描述情資進入資料庫的過程,扭曲成某人(或某個演算法)未來某時刻查詢並取得資料的行為,如此一來大幅擴充執法機關的權力。政府可以隨時查詢某人過去通訊記錄,尋找構陷他入罪的理由(所有人的通訊必定含有某些事的證據)。而任何新政府(未來國安局的混帳老闆)永遠可以輕鬆按幾下鍵盤,就能立刻追蹤所有人的電話或電腦,知道他們的身分、位置、現在在做什麼、旁邊有誰,以及他們過去的一切記錄。</p>
<hr>
<p>國安局將這類資訊稱為「後設資料」(metadata)。這個詞彙的字首「meta」通常指的是「以上」或「超越」,在此則是「有關」之意。而meta-data就是關於數據(data)的資料。更精確來說,它其實是「數據製造出的數據」(透過標籤、標記讓數據變得有用)。但最直覺理解的方式,是將它想成「活動數據」:你在裝置上從事活動與手機自行運作的記錄。舉例來說,手機後設數據可能包括:來電日期與時間、通話長短、來電與本機號碼以及通話位置。而電郵後設數據可能包括:發信者使用的電腦類型、位置與時間,電腦擁有者、寄件人與收信人是誰,何時何地收發信,以及其他能讀取此信的人時地等。透過後設數據的幫助,監視者能得知你昨晚入睡與今早起床的時間、每天逛了哪些地方、在哪裡待了多久,以及你接觸過的對象有誰、誰又與你聯繫過。</p>
<p>政府聲稱後設數據並未直接觸及通訊實質內涵,但上一段事實駁斥了這種說法。全球數位通訊數量龐大,想監聽所有電話、監看所有電郵是不可能的。即使有可能辦到,這些資訊也沒太大用處,而後設數據有辦法避開這樣的麻煩。我們最好不要認為後設數據只有好的用途,而該認定它是內容的精華部分,畢竟政府監控你的首要目標便是取得後設數據。</p>
<p>此外,還有一件事值得我們注意。你通常清楚知道自己製造出什麼樣的內容,像是在電話裡說了些什麼,或是在電郵裡寫了什麼。但你對於自己製造出的後設數據幾乎沒有任何掌控權,因為它是自動產生的。後設數據是由機器收集、儲存、分析與製造出來的,不需經過你的參與以及核准。你的裝置無時無刻都在為你溝通,不論你喜歡與否。人類依照自我意志進行溝通,但你的裝置不一樣,它們不會隱藏私人資訊,也不會為了保密使用密碼。它們只知道將手機訊號連上最近的基地台。</p>
<p>我們的法律通常落後科技至少一個世代,但如今對於通訊內容的保障卻高於後設數據,這真是極大的諷刺。事實上,情報單位對於取得後設數據有著更高興趣,因為這些活動記錄能讓他們見樹又見林,一方面賦予他們分析大量數據的能力、得以拼湊出事物全貌,另一方面又給予他們窺探個人私生活的機會、得以推斷這些人的行為模式。簡言之,監視者透過後設數據能得知你的所有一切,除了你的大腦在想什麼之外。</p>
<hr>
<p>我真正了解到這些新科技可能造成的危害。若我們這個世代不介入的話,那未來的情況只會更嚴重。我並不希望看到,當我們終於決定挺身而出時,一切抵抗卻是徒勞無功,若真是如此的話,那將是一大悲劇。未來的一代可能得面對充滿監控的環境,政府違法監控行為並非偶一為之、針對特定危險目標,而是持續性、無差別地擴及全國民眾。這就像是:你說的話逃不過政府耳朵,你做的事逃不過政府法眼,而你的紀錄檔案永遠留存在政府手裡。</p>
<p>一旦政府擁有四處收集情報的能力,加上情資得以永久儲存的系統,那他們便能隨便找個人或團體陷害,反正資料庫一定搜尋得到證據(如同我尋找機密檔案一樣),絕對能替他們安上合適罪名。</p>
<hr>
<p>如果我的親友、鄰居與廣大的民眾如此歡迎企業進到家中,讓他們在家的一舉一動都像上網一樣遭到嚴密監控,那我又何必對政府監控如此不滿。「智慧家庭」的變革可能還有五年才會到來,屆時亞馬遜Echo與Google Home等「虛擬助理」可望正大光明入住臥房,這些放在床頭櫃的裝置將近距離記錄並傳送你的一切活動,牢記你所有習慣與偏好(包含怪癖),之後再透過廣告運算法變現。我們日常生活產生的數據(或說容許生活被監控而產生的數據)能讓企業賺到大筆收入,卻讓我們的隱私蕩然無存。若說政府運用國家力量實施監控,將人民變成調查目標,那企業監控就是讓消費者變成商品,讓他們得以轉賣給其他企業、數據仲介商或廣告業者。</p>
<hr>
<p>雲端儲存服務協議的條文逐年增加,現在隨便一個版本都六千字起跳,大約是本書章節平均字數的兩倍。當我們選擇在線上儲存資料時,我們其實是放棄了資料的所有權。這些雲端公司可以決定為我們保留什麼樣的資料,同時任意刪除他們覺得不妥的內容。除非我們在自己的裝置或硬碟留下副本,否則他們刪除的資料就會永遠消失不見。如果資料引起爭議或違反協議的話,這些公司可以單方面刪除我們的帳號,讓我們無法取用自己的資料,但他們手中卻擁有副本,這意味著:他們能在我們未知情同意的情況下,將資料交給執法機關。總歸一句話,只有我們擁有自己的資料,才能保護它不受侵犯。沒有什麼資料是不受保護的,但沒有什麼資料是屬於私人的。</p>
<hr>
<p>美國基本法的存在,令執法單位更難執行工作。這並不是瑕疵,而是民主的真諦。按照美國法律規定,執法單位理應保護所有國民。當執法單位濫權時,法院應約束並糾正他們的行為,畢竟他們是社會上唯一能夠羈押、逮捕民眾並使用武力(包括致命武器)的人。而其中最重要的約束是,執法單位不得監控國民在家活動,也不能在未取得搜查令的情況下收集個資。但法律對於公眾場所的監控行為寬鬆許多,其中當然也包含多數人在街頭與人行道的活動。</p>
<hr>
<p>這樣一個由機器自動執法的世界,任誰都無法忍受。絕對的正義變成不公不義:一點小錯都會遭到嚴懲、法律全面貫徹到底。幾乎所有社會都存在許多不成文與成文的法律,其中有些條文早已過時,有些甚至連聽都沒聽過。舉例來說,馬里蘭州刑法第10-501條規定,通姦屬於輕罪行為、須支付十美元罰款。而根據北卡羅來納法律第14-309.8條規定,玩賓果遊戲超過五小時便算犯法。這些法律制訂於保守年代,卻不知為何從未遭到廢除。儘管我們自己沒有察覺到,但多數人生活絕不是黑白分明的,我們會任意穿越馬路、未確實做好資源分類、在人行道騎自行車,甚至連上陌生人的網路非法下載盜版等。換句話說,一旦法律貫徹到底,所有人都會變成罪犯。</p>
<hr>
<p>在獨裁的國家,國家擁有權利授與給人民。而在自由國家,人民擁有權利授與給國家。在前者,由於政府的允許,身為國民(subject)的人民才能擁有財產、受教、工作、宗教以及言論的權利。而在後者,人民擁有公民(citizen)身分,同意在一定時間內接受統治,但能定期透過選舉等制度更換政府。我認為,獨裁統治與自由民主間的差異,才是我們這個時代最主要的意識形態衝突來源,而不是東方與西方間的分歧(這是人為捏造並且充滿偏見),或是基督教對決伊斯蘭的宗教衝突。</p>
<p>獨裁國家通常都不是法治政府,而是以統治者意見為主。統治者要求國民服從政府,同時對異議分子極具敵意。相反的,自由民主國家不會或很少做出這樣的要求,反而是仰賴每位公民自願擔負起保護周遭所有人自由的責任,這是不分種族、膚色、信仰、能力、性傾向或性別的。任何集體保障並非取決於血統而是共識,最終導向平等主義的結果。雖然現實的民主經常無法達到理想狀態,但我仍堅信,這是最能「讓不同背景的人共同生活、在法律之前人人平等」的統治形式之一。</p>
<p>這種平等不僅由權利組成,更包含自由在內。事實上,民主國家的公民所珍惜的許多權利,在法律上都是以限制的方式來保障。透過限制政府權力創造出來的自由空間,使得這些權利得以存在。舉例來說,美國民眾之所以擁有言論「自由」,這是因為禁止政府不得制定限制該自由的法律;而新聞「自由」則是禁止政府不得制定法律限縮該自由。同樣的,宗教「自由」是禁止政府不得制定確立國教的法律;而和平集會與抗議的「自由」,是禁止政府不得制定任何法律來否定此自由。</p>
<p>在現代生活,我們擁有一致共識,那就是「隱私權」沒有模糊空間、不容政府侵犯。政府不得將髒手伸進此領域,法律唯一允許的辦法是透過搜索令。但這種搜索令無法「擴及所有人」(像是美國政府進行全民監控所聲稱取得的那種),而僅能基於合理理由針對特定人士或用途發出。</p>
<p>「隱私」這個詞彙有點虛無縹緲,因為難以定義,或說每個人的定義都不一樣,所有人對於隱私都有不同的詮釋。「隱私」的重要性不言可喻,大家想必都能體會。</p>
<p>正因為隱私缺乏一致性定義,導致多元先進民主國家的公民認為,他們必須交代渴求隱私的理由並將其定位為權利。但他們不必如此做,反而是政府必須說明何以侵害隱私的原因。拒絕主張自己的隱私權等同放棄此權利,將隱私讓渡給違憲政府或是「私人」企業。</p>
<p>我們根本無法忽視隱私的重要性,因為這與公民自由是相互依存的,你放棄自己的隱私,也會犧牲掉別人的隱私。你可能因為怕麻煩而選擇放棄此權利,或者你和多數人想法一樣,認為只有做不光明的事才需要隱私保護。但是,聲稱自己不需要或不想要隱私,因為沒有什麼事好隱瞞的這種說法,是假定所有人都不該或不能隱瞞任何事情,像是他們的移民身分、失業歷程、財務狀況與健康紀錄等。你假定,所有人(包括你在內)都樂於與他人分享宗教信念、政黨傾向與性生活,就如同有些人隨意透露自己的電影、音樂品味與閱讀偏好一樣。</p>
<p>說到底,你聲稱自己不在乎隱私,因為沒有事情好隱瞞,這就像是在說,你不在乎言論自由,因為你沒有意見。或是,你不在乎新聞自由,因為你不愛閱讀。你不在乎宗教自由,因為你不相信神。或是,你不在乎和平集會自由,因為反社會的你天性懶散、害怕人群。以上種種自由,今日對你來說也許不重要,但這不代表明日對你不重要,或對你的鄰居不重要,或是對於世界另一端的異議分子不重要。我用手機追蹤這群抗議群眾的動態,他們希望爭取到一點點的自由,而我的國家卻對於這些自由必欲除之而後快。</p>
<hr>
<p>我要說的是,我對於簡報內容不是那麼關心,例如,在我揭露的檔案中最為著名的是一份二〇一一年簡報檔中的一堆投影片,用六個面向來描述國安局新的監視立場:「無所不嗅,無所不知,無所不收集,無所不處理,無所不利用,無所不合夥」。這不過是公關講法,行銷術語。它的目的是要讓美國盟國留下印象:澳洲、加拿大、紐西蘭和英國,美國分享情報的主要國家(加上美國,即為五眼聯盟,Five Eyes)。「無所不嗅」表示找尋資料來源;「無所不知」表示查出有些什麼資料;「無所不收集」表示獲取那些資料;「無所不處理」表示分析資料以找出可用的情報;「無所不利用」表示利用那些情報以推動國安局的目的;「無所不合夥」表示與盟國分享新的資料來源。這六個面向容易記住、容易推銷,並且準確表達出國安局的野心規模以及跟外國政府共謀的程度,卻無法讓我了解究竟這項野心是如何在技術層面落實的。</p>
<p>讓我了解更多的是我從FISA(外國情報監控法)法院找到的一份命令,要求一家民間企業將客戶的私人資訊交給聯邦政府。這類命令通常是根據公共立法授權而在全國發出,可是,命令內文、甚至發出命令,都被列為最高機密。根據「愛國者法案」(Patriot Act)二一五條款,亦即「企業紀錄」條款,政府有權向外國情報監控法院取得命令,強制第三方提供與外國情報或反恐調查「相關的任何實體東西」。可是我所找到的這份法院命令明白表示,國安局祕密地將這項授權詮釋為一份許可,可收集所有「企業紀錄」、後設資料、經由威瑞森(Verizon)、AT&T等美國電信公司的電話通訊,「在經常性的日常基礎上」。當然,這包括美國公民之間的電話通訊紀錄,而此舉是違憲的。</p>
<p>此外,「外國情報監視法修正案」七〇二條款准許情報體系鎖定任何美國境外可能傳播「外國情資」的外國人,這個廣泛項目的可能對象包括新聞記者、公司員工、學術界、救援人員和無數其他沒有做錯事的無辜者。國安局把這項法案拿來做為其兩項最著名網路監視計畫的依據:稜鏡計畫(PRISM)和上游收集(Upstream Collection)。</p>
<p>稜鏡計畫讓國安局可以定期由微軟、雅虎、谷歌、臉書、Paltalk、YouTube、Skype、AOL及蘋果收集資料,包括電郵、照片、影音聊天、網路瀏覽內容、搜尋引擎搜尋,以及所有儲存在他們雲端的其他數據,將這些公司變成知情的共犯。不過,上游收集更具侵入性。它可以固定從私部門網路基礎設施,像是全球網路流量的轉換器與路由器,經由太空衛星和高容量海底光纖電纜,直接抓取資料。這項收集是由國安局特別資源行動小組負責,他們打造祕密監聽設備,植入全球網路服務供應商的企業設施內部。加總起來,稜鏡計畫(由網路服務供應商的伺服器強制收集)和上游收集(由網路基礎設施直接收集),確保全球資訊都可受到監視,包括儲存的與傳輸的資訊。</p>
<p>我的調查的下個階段是要查出這種收集是如何實際辦到的,也就是說,檢視解釋哪些工具支援這項計畫的文件,以及他們如何由拖網式收集的大量通訊中挑選值得進一步檢查的資訊。困難之處在於任何簡報都沒有提到這種資訊,不論機密程度為何,都只能有工程圖解和示意圖。這些是我想找到的最重要資料。不同於五眼推銷簡報,它們將可確切證明我所看到的監視能力不只是一個咖啡因攝取過量的計畫經理人的幻想而已。身為一個不斷被要求加快速度與提高產能的系統工程師,我十分清楚這些機構有時會在實際研發出技術之前就搶先公布,有時是因為一個懸崖型推銷人員承許過多的承諾,有時是出於純粹的野心。</p>
<p>可是,上游收集的技術確實存在。我後來明白,這些工具是國安局集體監視系統最具侵入性的環節,因為它們最貼近用戶,亦即最貼近被監控的對象。想像你坐在電腦前想去瀏覽一個網站,你開啟一個瀏覽器,鍵入一個網址,然後按入「Enter」。網址其實是一項請求,這項請求會去找它的目的地伺服器。在旅程的途中,在你的請求抵達伺服器之前,便會經過「亂流」(TURBULENCE),國安局最強大的武器之一。</p>
<p>明確來說,你的請求會經過好幾個堆疊起來的黑色伺服器,加起來大約是四層書櫃的體積。它們裝置在盟國、美國大使館和美國軍事基地大型私人電信建築物裡的特別房間,內建兩項重要工具。第一個是「混亂」(TURMOIL),負責被動式收集,亦即複製進來的數據。第二個是「渦輪」(TURBINE),負責主動式收集,亦即主動監控使用者。</p>
<p>你可以把「混亂」想成是站在網路流量必須通過的隱形防火牆前的警衛。看到你的請求後,它會檢查自己的後設資料,找尋被標示為值得「提高」注意的選擇器,或者「標準」。這些選擇器可能是國安局選擇或懷疑的任何對象:一個特定的電郵地址,信用卡或電話號碼;你的網路活動的來源地或目的地;或者只是一些關鍵字,例如「匿名網路代理」或「抗議」。</p>
<p>假如「混亂」覺得你的流量可疑,就會通知「渦輪」,後者便會將你的請求轉到國安局的伺服器。在那裡,演算法會決定要用該機構的哪個惡意程式來監控你。這個選擇係依據你瀏覽的網站種類和你的電腦軟體與網路連結。選定的惡意程式回傳到「渦輪」(經由QUANTUM套裝軟體的程式,如果你好奇的話),再由後者注入流量頻道,連同你請求的網站一同傳送給你。最終結果是:你得到你想要的內容,連同你不想要的監視,而這一切在不到六八六毫秒便發生。你完全不知情。</p>
<p>等惡意程式進入你的電腦,國安局不但可以存取你的後設資料,還有你自己的資料。你的整個數位人生現在都屬於他們了。</p>
<hr>
<p>只有在這種背景下才能完全理解美國政府和洩密的關係。如果有意料之外的好處,他們就會原諒「未經許可的」洩密,並且在「經過許可的」洩密造成傷害時選擇遺忘。然而同樣都是造成傷害、而且不是經過許可的洩密,它們本身就是不合法的,但市政府卻會做出不同的反應,是什麼因素造成有的揭露可以被允許?有的卻不行?</p>
<p>答案就是權力和控制。如果這次揭露不會威脅到一個機構的基礎權力,才有可能被接受。如果一個機構裡面的不同部門,從收發室到管理辦公室,都有相同的權力可以討論內部事務,那麼管理階層就是放棄了資訊管理的權力,然後整個組織的運作就會產生危機了。爭取發言的平等權,獨立於組織的管理或決策階級之外的,就是「吹哨」這個名詞的適當意義——這種行為尤其對美國情報體系產生威脅,它是在法律允許的神祕面紗下以嚴格區隔的方式來運作。</p>
<p>依照我的定義,「吹哨者」是一個人經歷了艱苦的經驗,認為他們在機構內的生活已經不符合外界廣大社會的原則,以及對這個社會的忠誠,而這個機構應該要對社會負責。這個人知道自己不能持續待在這個機構了,也知道這個機構不能或不會被廢除。然而,重組這個機構卻是有可能的,所以他吹響哨子,揭露資訊,讓機構負擔來自大眾的壓力。</p>
<p>針對我的情況,這是一個適當的敘述,還有一個很重要的附加條件:所有我刻意揭露的資訊都是最高機密。要揭發一個祕密計畫,就必須揭發更大的機密系統,揭發它,不是因為美國情報體系宣稱自己是國家的絕對權力,而是美國情報體系濫用這種有限的特權來顛覆民主監督。如果不揭發這整個機密系統,就不可能恢復公民和政府之間的權力均衡。這種希望能恢復的動機就是吹哨的基礎——揭露不是因為對政府有異議或是反對才做出的激進舉動,而是為了掉頭而做出的普通舉動——讓船掉頭回港,在這裡它會被拆解、整修、補起洩漏的地方,才能有重新出發的機會。</p>
<p>全面揭露關於全民監視的全部設備——不是由我來,而是由媒體來,媒體受到權利法案保護、是美國政府實際上的第四權,對於這種規模的犯罪,這是唯一合適的反應。畢竟光是揭露一個特定或一系列濫用職權的行為是不夠的,他們可以停止(或假裝停止)這些行為,但是原封不動地保留其他不為人知的設備。我打算揭發一個全面的事實——美國政府研發並運用了一套全球全民監視系統,但是卻沒有讓美國公民得知或同意。</p>
<hr>
<p>考慮到我所冒的風險,我需要找出我能信任、大眾也可以相信的人。我需要認真、謹慎、獨立而可信賴的記者。他們必須有絕佳能力,能在區別我的懷疑與證據證明的事項之間,對我進行挑戰,當政府不當指控他們的報導將危及他人性命時,對政府提出質疑。最重要的是,我必須確保我挑選的人,在面臨前所未有的壓力時,不會屈服在權力之下。</p>
<p>我並沒有將網撒得太廣,以免影響這個任務,但仍廣到足以避免一個錯誤點,那就是《紐約時報》的問題。一個記者、一份刊物或一個國家的刊物都不夠,因為美國政府已經顯現扼殺此類報導的決心。理想的情況是,我同時把檔案交給每位記者,自己不會留任何一份。這可以把審查焦點轉移到他們身上,以防一旦我被逮捕,真相仍有機會公諸於世。</p>
<p>當我縮減這份可能合夥人名單時,我發現這個方向是錯誤的,或者是浪費時間。與其自己挑選記者,我應該讓我企圖揭密的系統為我選人。我決定,最好的合夥人應該是國家安全機構已經鎖定的記者。</p>
<hr>
<p>事實上,我們以為的刪除技術從來不曾存在過。刪除不過是一種詭計、一種臆想、一種謊言,是一個電腦為了讓你安心而跟你說的不高明謊言。雖然刪除的檔案在你眼前不見了,卻沒有真正消失。就技術而言,刪除其實只是一個過渡的形式,一種寫入的形式。一般來說,當你按下刪除一個檔案,它的數據仍安然無恙,深埋在磁碟的某處。有效的現代作業系統,並不會單純為了刪除而設計用來在磁碟裡深入搜尋。相反的,只有電腦的檔案表,也就是記錄每個檔案儲存所在的地圖,被改寫為:「我不再使用這個檔案,且此檔案已經失去重要性。」意思是說,就像在一座廣大圖書館裡被忽略的一本書,原本應該消失的檔案,只要你努力的找,還是可以找到。如果你只是消除書目,書本本身是仍然存在的。</p>
<p>這實際上可以利用實驗來證明。下回你複製一份檔案時,不妨想想為什麼複製檔案要花那麼久的時間,但是刪除檔案只需要一下子。答案是,刪除僅僅是把一個檔案隱藏起來而已。電腦不是設計來矯正錯誤的,而是用來掩藏錯誤,而且是只對不知道去哪裡尋找的人士掩藏。</p>
<hr>
<p>刪除是監視者的美夢、被監視者的噩夢,加密則是、或者說應該是所有人的現實。這是對抗監視的唯一真正屏障。如果你的儲存磁碟一開始就加密,你的敵人就無法在裡頭翻尋你已刪除的檔案或是任何東西,除非他們有加密金鑰。如果你的收件匣所有電子郵件都有加密,谷歌便無法透過讀取來收集你的個資,除非他們有加密金鑰。如果你將經過澳洲、英國、美國、中國或俄羅斯的不友善網絡的相關通訊全部加密,間諜便無法讀取,除非他們有加密金鑰。這是加密的基礎原則:金鑰持有者掌握一切權力。</p>
<hr>
<p>在我日後交給新聞記者的文件裡,國安局形容XKEYSCORE是「最為全面性」的工具,用以搜尋「使用者在網路上所做的幾乎每一件事。」我研究的技術規格則更為詳盡地說明這是如何辦到的,藉由「封包」與「切分」,亦可以將使用者的線上對話切割成可以管理的封包以進行分析。雖然我已經可以說明,但我仍然最想看到它的實際運作。</p>
<p>簡單來說,這是我在科學事實中所見過最接近科幻小說的東西:你在這個介面可以輸入幾乎所有的地址、電話號碼或IP網址,然後搜尋近期的線上活動。在某些個案,你甚至可以重新播放他們線上對話的紀錄,你可以看到他們桌機螢幕畫面。你可以閱讀他們的電郵、瀏覽紀錄、搜尋紀錄、社群媒體貼文,所有的一切。你可以設定通知,每當你關注的人員或裝置上線時就會跳出通知。你可以搜尋網路數據封包,看到一個人的搜尋逐字跳出,因為許多網站在每個字母鍵入時便會傳輸出去。這就像看著一份「自動完成」(autocomplete),螢幕上閃過字母與單字。但是,輸入動作的不是電腦而是人類:這是「人工完成」(humancomplete)。</p>
<p>我在米德堡的那幾個星期,以及我在夏威夷博思艾倫的短暫任職,讓我親眼目睹以前只在內部文件上所讀過的濫權行為實際發生。看到這些,我才明白我在體系層級的地位跟構成立即傷害的原爆點差多遠。我只能想像我和國安局局長或美國總統之間地位的懸殊。</p>
<p>我並沒有在XKEYSCORE輸入國安局局長或美國總統的名字,但在足夠時間熟悉這個系統之後,我才知道我其實可以。所有人的通訊都在系統裡——所有人。剛開始我擔心我如果搜尋國家高層,我會被逮到並被革職,或者更糟。可是,要偽裝一項搜尋其實很簡單,即使是最知名人物,只要用一種電腦格式將我的搜尋條件編碼即可,那種格式在人類看起來像是塗鴉,但XKEYSCORE卻能完美理解。如果有哪位負責審查搜尋的督察人員費事去深入檢查,他們只會看到片段的亂碼,但我卻能夠搜尋最高法院法官或國會議員最私密的活動。</p>
<p>就我所知,我的新同事都不打算如此大規模地濫用他們的權力,雖然他們如果真的這麼做了,也沒有提起過。無論如何,當分析師想到濫用系統時,他們在意的不是專業上的目的,而是個人目的。這導致一種稱為LOVEINT(愛人情報)的行徑,這是對於HUMINT(人員情報)及SIGINT(訊號情報)的下流笑話,對情報的嘲弄。分析師會利用國安局的系統去監視他們現任及前任情人以及關心的對象,閱讀他們的電郵,竊聽他們的電話,在線上追蹤他們。國安局員工知道,只有最愚蠢的分析師才會被當場逮到,雖然法律明文指出為個人用途從事任何種類的監控將至少被關上十年,國安局歷史上沒有一個人曾因為這種罪名而被關上一天。分析師知道政府絕對不會公開起訴他們,因為在你不願承認有這種系統存在的前提之下,你無法讓一個人為了濫用全民監視的祕密系統而被定罪。當我和兩名高明的基礎設施分析師坐在國安局總部V22保險庫的牆壁前,我才明白這種政策的代價。他們的工作空間裝飾著一幀《星際大戰》電影知名角色丘巴卡(Chewbacca)的七英尺高照片。其中一人向我仔細說明他的目標的安全例行公事時,我才明白攔截的裸照是一種非正式的辦公室貨幣,因為他的同事不停坐在椅子上轉動,用一個笑容來打斷我們說:「瞧瞧她。」我的指導者千篇一律回答:「中獎了!」或「好極了!」彷彿有一條不成文的交易規定,假如你找到一張漂亮目標的裸照或影片,或是跟監控目標通訊的人的裸照或影片,至少在沒有女性在場的時候,你就必須秀給其他人看。這樣才能知道你可以信任彼此:你參與了其他人的犯罪。</p>
<p>使用XKEYSCORE之後,你很快便會知道,幾乎全世界每個上網的人都至少有兩個共同點:他們都曾經看過色情內容、他們都儲存了家人的照片和影片。不論性別、種族和年齡,幾乎每個人都一樣,包括最邪惡的恐怖分子和最善良的老年人,他們或許是最邪惡恐怖分子的祖父母、父母或表親。</p>
<hr>
<p>在我往返庫尼亞沿街掃描時——原本二十分鐘的車程可能變成兩小時的無線網路掃描——我都在搜尋不同國家,想要找尋跟記者碰面的地點。感覺上我是在挑選自己的監獄,甚至是墓園。五眼聯盟的國家顯然都不在考慮之列。事實上,所有歐洲國家也都剔除,因為你不能指望這些國家在面臨美國強大壓力之下,還能堅守拒絕引渡政治犯的國際法。非洲與拉丁美洲也去不得,美國在當地向來有犯罪也不會被處罰的紀錄。俄羅斯也被排除,因為那是俄羅斯,而中國是中國:這兩國完全無法無天。美國政府不必做什麼事,只要指著地圖,便可以抹黑我。中東的情況更糟糕。有時看起來,我人生最艱鉅的駭客任務不是搜索國安局,而是找尋一個獨立到足以抵抗美國、且自由到不會干涉我的行動的會面地點。</p>
<p>經過一番消去法,只剩下香港。就地緣政治而言,那裡是我所能找到最接近無人區(no-man’s-land)的地方(在雙方發生戰鬥之前,無人敢進入的地帶),但有著蓬勃的媒體和抗議文化,更別說網路大致上不設限。那裡是一個奇異的地方,一個開明的世界城市,表面上的匿名可以隔絕我與中國,至少限制北京在當下公然對我或記者採取行動的能力。雖然香港實際上屬於北京勢力範圍,但可以減少美國片面干預的可能性。但在無法保證安全的情況下,這已足夠讓我有緩衝時間。反正,我不會有什麼好下場:我所能期望的最佳情況是在我被逮捕前,把真相公諸於世。</p>
<hr>
<p>自從《衛報》網站六月九日釋出我的影片後,我便被鎖定了,就像我背後有個標靶。我深知,這些蒙受羞辱的機構絕不會善罷甘休,一直到我落入他們手中為止。過些時候,他們也可能轉移目標、騷擾我心愛的人,同時貶低我的人格,他們會四處打探我私人生活與工作情況,尋找任何可以抹黑我的資訊,或是把握每次造謠的機會。我對於這整個過程並不陌生,畢竟我待在情報單位時讀了不少機密資料,加上我也研究過吹哨者與洩密者的下場。我查過這些英雄的故事,包括過去的丹尼爾.艾斯柏格與安東尼.羅素,以及較近期的托馬斯.塔姆(Thomas Tamm)。塔姆曾在美國司法部情報政策與審查辦公室擔任律師,他爆料政府於二〇〇〇年中期非法竊聽民眾。另外還包括德雷克、賓尼、魏比與魯米斯。魯米斯就像是數位時代的佩里.弗爾沃克(Perry Fellwock),後者早在一九七一年時便揭露當時尚不為人知的國安局機構存在,此舉促使參議院丘奇委員會(情報特別委員會前身)要求國安局僅能收集外國情報,不得監控國內民眾。當然還有舉世聞名的美國陸軍一等兵雀兒喜.曼寧,她因洩露美國戰爭罪行而遭軍事法庭判刑三十五年。她服刑七年後便獲得特赦,原因是她在關禁閉時受到不公平對待,因此引發國際社會抗議。</p>
<p>不管這些人是否入獄,他們多少都得面對反彈力量,其中多數是非常殘忍的人格摧毀,而背後依據則是政府通過濫權獲得的情報。若這些人私下通訊時曾表現憤怒情緒,那他們會被說是「挾怨報復」。若他們看過心理或精神科醫生,或是在圖書館借過類似書籍,那他們會被認定成「精神錯亂」。若他們曾喝醉酒,那他們必定是酒鬼。若他們有過外遇,那就是生性淫亂。其中不少爆料者因此傾家蕩產。情報單位根本不必與這些異議人士交手,直接破壞他們的名聲還比較快,反正只要動手調出檔案,再放大不利情報或憑空捏造證據即可。</p>
<hr>
<p>六月十四日,美國政府以間諜法罪名起訴我,起訴書不對外公開。六月二十一日,他們正式要求引渡我回美國。我知道,這是我該離開的時候,而這天恰好也是我的生日。</p>
<p>正當美國國務院提出引渡要求之際,我的律師收到聯合國難民署的回應,他們表明無法協助我取得庇護。而香港政府(不論是否受到中國施壓)抗拒聯合國呼籲,不願在他們的領土上提供我國際保護,並宣稱他們必須顧及美方要求。換句話說,香港要我回到美國並在牢中向聯合國求助。我不只是孤單一人,且在各國都不受歡迎。如果我想自由地離開香港的話,我必須現在就走。我清空手中四部筆電資料並銷毀加密金鑰,這代表我再也無法取用機密文件,即便美國政府強迫我也無法做到。我將僅有的幾件衣服打包好便起身離開。「芳香的海港」根本沒有我容身之處。</p>
<hr>
<p>美國政府決定以間諜法起訴我,我被控犯下政治罪,意思是受害者是政府而非個人。按照國際人道法規定,遭控犯下此罪的人通常不會遭到引渡,因為起訴政治犯經常是獨裁國家打壓異議的手段。理論上,這代表吹哨者在全球各地都應獲得同等保障。但實際上卻不是這麼一回事,特別是當你的對手是自認正義的美國政府時。表面上聲稱扶植海外民主國家的美國政府,私底下卻成立由私人承包的祕密機隊,專門用於「非常規引渡」,也就是部分人口中說的「綁架」。</p>
<hr>
<p>我們在莫斯科機場受困長達四十天四十夜。在這段期間,我總共向二十七國申請政治庇護。沒有任何一個國家膽敢起身對抗美國,有些國家一口回絕,部分國家則表示,除非我抵達他們境內,否則無法考慮這項請求,而這根本是不可能的事。最後,唯一同情我的國家元首只有一個,那就是「漢堡王」,它從未否決我大啖華堡(內含番茄與洋蔥)的請求。</p>
<p>過了不久,我滯留機場的消息傳遍全球,俄國當局最後也覺得有些麻煩。七月一日,玻利維亞總統埃沃.莫拉萊斯(Evo Morales)結束天然氣輸出國論壇年度大會後,他搭乘專機從莫斯科伏努科沃機場離開。由於莫拉萊斯曾對我的處境表達同情,美方懷疑我藏匿在專機裡,於是施壓義大利、法國、西班牙與葡萄牙不准飛機進入他們國家領空,最終導致專機迫降於奧地利首都維也納。此專機遭到停飛、搜索,直到確認沒有我的蹤跡才放行。這嚴重侵害玻利維亞國家主權,聯合國也予以譴責。此事令俄國顏面無光,因為他們無法確保來訪的國家元首順利回家。而這也讓俄國政府與我都確信一點:任何美國懷疑我用來偷渡的飛機,恐怕都難逃迫降與停飛的命運。</p>
<p>俄國政府決定盡快擺平此事,並還給莫斯科機場一個清淨,別老是被大批媒體包圍。八月一日,俄國決定給予我暫時庇護。莎拉和我得以離開謝列梅捷沃機場,但莎拉能回到美國老家。我們一起共患難的時光,讓我和莎拉變成終生摯友。我永遠感激,她這幾個禮拜以來的陪伴,她是如此地正直坦率、堅韌勇敢。</p>
<hr>
<p>如果你在閱讀本書時有任何時刻因為一個名詞而停了下來,你想要釐清或進一步調查,於是在搜尋引擎鍵入該名詞,而且如果那個名詞碰巧有些可疑,像是XKEYSCORE,那麼我要恭喜你:你已落入系統了,淪為自己好奇心的受害者。</p>
<p>但是,即便你沒有在線上搜尋任何東西,心懷不軌的政府仍然不費力氣便可查出你有閱讀本書。最起碼,它不費什麼力氣便可查出你有這本書,不論你是否非法下載或者在線上購買精裝本,或者在實體商店用信用卡購買。</p>
<p>你只不過想要閱讀而已——參與這項最親密的人類行為,透過語言進行思想交流。但這已經太過足夠了。想要與世界聯繫的自然慾望,便足以讓你的生活跟這個世界連接起來,將你自己帶進一系列全球獨特的識別碼,例如你的電郵、電話和個人電腦IP網址。藉由創造一個遍及世界的系統,經由每一種可能的電子通訊管道來追蹤這些識別碼,美國情報體系讓自己掌握權力,得以記錄與永久儲存你人生的資料。</p>
<p>而這只是開始而已。因為一旦美國諜報機構發現他們可以被動收集你所有的通訊,他們便會開始主動惡搞。他們在發給你的訊息中植入攻擊程式碼,亦即「漏洞利用」(exploit),藉此取得你的文字以外的資訊。現在他們有能力全面控制你的整體裝置,包括照相鏡頭和麥克風。這意味著,如果你在手機、平板電腦,或是任何現代機器上閱讀一本書,不論讀到哪裡,他們都可以追蹤及讀取你。他們可以分辨你翻頁的速度是快是慢,你有沒有一章接一章看下去或者是跳著看。他們會樂意忍受看著你的鼻孔,看著你邊讀邊扭動嘴唇,只要他們可以獲得想要的資料,確定辨識你這個人就好了。</p>
<p>這是二十年來無節制發展科技的下場,政治與專業階級夢想著成為全民主宰的最終產物。無論何地、何時及何事,你的生活如今已成為一本翻開的書,能夠隨時被讀取。</p>
<hr>
<p>或許在完美的世界,也就是並不存在的烏托邦裡,單憑法律就可以讓這些工具失去作用。但在我們現在所在的世界,它們變得極有必要。修改法律絕對比修改技術標準來得更加難以達成,只要法律創新落後科技創新的一日,就一定會有機構試圖濫用這種科技和資訊的不對等來助長他們自己的利益。這時便需要依賴獨立、開放原始碼的硬體和軟體開發者來填補這種差距,提供法律無法或者不願意確保的重要公民自由保障。</p>
<hr>
<p>早在出生前,當科技偵測到我們在子宮裡,我們便開始創造這份資料,即使在我們死後,我們的資料仍不斷增加。當然,我們有意識地製造的記憶、選擇保存的紀錄,不過是我們人生被企業與政府的監控所擰出來的資訊的其中一個小碎片,而大多是無意識地,或是未經我們同意。我們是地球歷史上首度遭遇這種情況的人,是首度背負著永久檔案的人,也就是說我們被收集的紀錄將永久存在。正因為如此,我們才有特殊責任。我們必須確保自己過去的紀錄不會被用來對付我們,或者對付我們的子孫。</p>
<hr>
<p>演算法用以分析資料,找尋既定行為模式以推斷未來行為,這種數位預言只是比看手相的類比方法稍微準確一些而已。一旦你深入挖掘用以預測的實際技術機制,你便會了解這種科學實際上是反科學,而且名稱大錯特錯:預測其實是操弄。一個網站告訴你說,由於你喜歡這本書,所以你或許也喜歡國家情報總監克拉柏或前國家安全局局長海登的書,這並不是什麼有根據的猜測,而是一種「微妙的強制」機制。</p>
<p>我們不能放任自己受到這樣的利用,被利用來對抗未來。我們不能允許自己的資料被用來向我們推銷絕對不可以出賣的東西,例如新聞。如果袖手不管,所看到的新聞將只是我們想要的新聞,或是當權者希望全民看到的新聞,而不是必要的坦白共同對話。不能放任我們所受到的全面監控,以之來「計算」我們的公民分數,或是「預測」我們的犯罪行為;我們會受什麼教育,會找到什麼工作,或是能否受教育或找工作;依據金融、法律和醫療紀錄來歧視我們,更別說還有族群或種族,這些都是我們的資料的構成因素。至於個人最私密的資料,我們的基因資訊:如果坐視這種資訊被用來辨識我們,那麼它也會被用來加害我們,甚至修改我們,按照試圖控制全民的科技概念,重新塑造我們的人性本質。</p>
<p>當然,以上種種全部都已經發生了。</p>
<hr>
<p>以上摘自:</p>
<p><img src="https://i.loli.net/2019/11/27/uPxiWOLqvnKmRBd.jpg" alt="《永久檔案》"><br>
<a href="https://zh.wikipedia.org/wiki/%E6%B0%B8%E4%B9%85%E6%AA%94%E6%A1%88">《永久檔案》</a><br>
作者: 愛德華・斯諾登 <br>
出版社: 時報文化出版社 <br>
ISBN: 9781250237231</p>
为Chrome for Windows设置临时Socks5代理
https://acuario.xyz/posts/setting-socks5-with-chrome-for-windows/
2023-09-27T18:25:39+00:00
2019-11-25T21:53:06+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>如何为 Windows 的 Chrome 设置 Socks5 代理,网上千篇一律的文章都是教你使用 Chrome 扩展 <a href="https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=zh-CN">Proxy SwitchyOmega</a> 来实现。</p>
<p>但无法使用代理突破网络封锁,又怎么在 Chrome 扩展商店下载使用 Proxy SwitchyOmega 呢?(Chrome 67 以后不再支持安装本地 <code>.crx</code> 扩展)这就成了先有鸡还是先有蛋的问题。</p>
<p>如果局域网内已有可用的 Socks5 代理服务,<strong>在不安装任何程序的情况下</strong>(我就是不想装什么 Proxifier),其实简单几步即可实现:</p>……
<p>如何为 Windows 的 Chrome 设置 Socks5 代理,网上千篇一律的文章都是教你使用 Chrome 扩展 <a href="https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=zh-CN">Proxy SwitchyOmega</a> 来实现。</p>
<p>但无法使用代理突破网络封锁,又怎么在 Chrome 扩展商店下载使用 Proxy SwitchyOmega 呢?(Chrome 67 以后不再支持安装本地 <code>.crx</code> 扩展)这就成了先有鸡还是先有蛋的问题。</p>
<p>如果局域网内已有可用的 Socks5 代理服务,<strong>在不安装任何程序的情况下</strong>(我就是不想装什么 Proxifier),其实简单几步即可实现:</p>
<ol>
<li>关闭所有 Chrome 窗口和进程</li>
<li>右键点击 Chrome 快捷方式,查看属性,获得 Chrome 程序的目标位置,如:</li>
</ol>
<pre tabindex="0"><code>C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
</code></pre><ol start="3">
<li>打开运行(Ctrl+R),输入命令:</li>
</ol>
<pre tabindex="0"><code><chrome.exe> --show-app-list --proxy-server="SOCKS5://<address>:<port>"
</code></pre><p>例如:</p>
<pre tabindex="0"><code>C:\Program Files (x86)\Google\Chrome\Application\chrome.exe --show-app-list --proxy-server="SOCKS5://192.168.1.10:1080
</code></pre><ol start="4">
<li>运行上述命令后打开的 Chrome 已经自动设置了 Socks5 临时代理,如果 Socks 服务正常的话,你可以畅快地访问 Chrome 扩展商店安装 Proxy SwitchyOmega 了。后面的骚操作就不多说了。</li>
</ol>
<p>写到这里突然想起来,其实 Socks5 服务<strong>有没有在局域网内都无所谓</strong>,只要正确设置地址和端口即可。</p>
<p>别忘了这是临时代理,除非运行上述命令启动 Chrome,否则重启 Chrome 代理设置失效。</p>
实用浏览器小书签
https://acuario.xyz/posts/shortcut-bookmarklet/
2023-09-27T18:25:39+00:00
2019-11-14T21:02:40+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>由于众所周知的原因,非会员下载百度网盘的速度慢的令人发指,所以目前最推荐的度盘下载工具是 <a href="https://pandownload.com/">Pandownload</a>,但是软件本身需要登录百度账号,如果账号被限速也没辙。经笔者实测,发现 Pandownload 的<a href="https://www.baiduwp.com/">网页版</a>配合 Aria2 可以无账号高速下载。不过这不是本文重点。</p>
<p>Pandownload 允许用户将度盘分享链接中的 <code>baidu</code> 修改为 <code>baiduwp</code> 后进行访问,可直接解析资源后下载。频繁点击 URL 修改实在麻烦。受<a href="https://acuario.xyz/simplify-URL/">《用 JavaScript 为 URL 瘦身》</a>一文的启发,想到可以用 JS 制作小书签,即点即用。</p>
<p>不知道小书签为何物的话,可以参阅少数派的<a href="https://sspai.com/post/45662">这篇文章</a></p>……
<p>由于众所周知的原因,非会员下载百度网盘的速度慢的令人发指,所以目前最推荐的度盘下载工具是 <a href="https://pandownload.com/">Pandownload</a>,但是软件本身需要登录百度账号,如果账号被限速也没辙。经笔者实测,发现 Pandownload 的<a href="https://www.baiduwp.com/">网页版</a>配合 Aria2 可以无账号高速下载。不过这不是本文重点。</p>
<p>Pandownload 允许用户将度盘分享链接中的 <code>baidu</code> 修改为 <code>baiduwp</code> 后进行访问,可直接解析资源后下载。频繁点击 URL 修改实在麻烦。受<a href="https://acuario.xyz/simplify-URL/">《用 JavaScript 为 URL 瘦身》</a>一文的启发,想到可以用 JS 制作小书签,即点即用。</p>
<p>不知道小书签为何物的话,可以参阅少数派的<a href="https://sspai.com/post/45662">这篇文章</a></p>
<p>本文提供一些笔者自己收藏使用的小书签,拖动下方链接到浏览器收藏栏即可保存。</p>
<ul>
<li>
<p>下载百度网盘:<a href="javascript:(function(){ location.href = location.href.replace('baidu', 'baiduwp'); })();">度盘下载</a></p>
</li>
<li>
<p>下载百度文库:<a href="javascript:(function(){ location.href = location.href.replace('baidu', 'baiduvvv'); })();">文库下载</a></p>
</li>
<li>
<p>查看当前网页在各大搜索引擎的网页快照:<a href="javascript:(function(){ location.href = location.href.replace(location.hostname, 'his.sh/'+location.hostname); })();">View Cache</a></p>
</li>
<li>
<p>在<a href="https://archive.org/">互联网资料馆</a>保存当前网页的快照:<a href="javascript:(function(){ location.href = 'https://web.archive.org/save/'+location.href;})();">Save Cache</a></p>
</li>
<li>
<p>繁体转换为简体:<a href="javascript:(function(){var s=document.getElementById('tongwenlet_cn');if(s!=null){document.body.removeChild(s);}var s=document.createElement('script');s.language='javascript';s.type='text/javascript';s.src='https://git.oschina.net/runningcheese/JiathisQR.js/raw/master/bookmarklet_cn.js';s.id='tongwenlet_cn';document.body.appendChild(s); })();">繁转简</a></p>
</li>
<li>
<p>最好用的网页翻译——彩云小译:<a href="javascript: void((function () { if (!document.body) { return } var popup = document.querySelectorAll('.cyxy-target-popup'); if (popup && popup.length > 0) { return } try { var trs = document.createElement('script'); trs.type = 'text/javascript'; trs.charset = 'UTF-8'; trs.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'caiyunapp.com/dest/trs.js'; document.body.appendChild(trs); } catch (e) { alert(e); } document.addEventListener('securitypolicyviolation', function handler(e) { console.error('securitypolicyviolation', e); alert('由于当前网站的内容安全策略(Content Security Policy),小译无法启动翻译程序,您可以在Chrome Web商店搜索彩云小译(LingoCloud)下载插件,或者将网页保存在本地(右键 -> 另存为)进行翻译,也欢迎您在手机应用商店下载彩云小译App :)'); document.removeEventListener('securitypolicyviolation', handler); });})());">小译</a></p>
</li>
<li>
<p>转换 HTTP 为 HTTPS:<a href="javascript:(function(){ if (location.href.indexOf('https://') == -1) { location.href = location.href.replace('http://', 'https://'); } })();">https</a></p>
</li>
<li>
<p>复制 URL 但不转换内部中文:<a href="javascript:(function(){ const el = document.createElement('textarea'); el.value = decodeURIComponent(location.href); document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); })();">复制URL</a></p>
</li>
<li>
<p>去除 URL 跟踪代码:<a href="javascript: (function() { function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); var r = window.location.search.substr(1).match(reg); if (r != null) return r[2]; return null; } var site = window.location.href.match(/^http(s)?:\/\/[^?]*/); var id = getQueryString('id'); var q = getQueryString('q'); if (id != null) { var pureUrl = site[0] + '?id=' + id; } else if (q != null) { var pureUrl = site[0] + '?q=' + q; } else if (site[0].substr(site[0].length - 13) == 'view_shop.htm') { var pureUrl = window.location.protocol + '//' + window.location.host; } else { var pureUrl = site[0]; } /* Apple Store 将国家设置为中国 Start */ pureUrl = pureUrl.replace(/^http(s)?:\/\/itunes\.apple\.com\/(\w{2}\/)?([^\/]+)\/([^\/]+\/)?(id\d+).*/, 'https://itunes.apple.com/cn/$3/$5'); /* Apple Store 将国家设置为中国 End */ /* Chrome Store 地址精简优化 Start */ pureUrl = pureUrl.replace(/^http(s)?:\/\/chrome\.google\.com\/webstore\/detail\/[^\/]+\/([a-z]{32}).*/, 'https://chrome.google.com/webstore/detail/$2'); /* Chrome Store 地址精简优化 End */ if (pureUrl) { window.history.pushState({},0,pureUrl); } })();">链接洗白白</a></p>
</li>
</ul>
<p>网络上有很多提供小书签的网站,比如<a href="https://www.runningcheese.com/bookmarklet">这个</a>,如果你会 JavaScript 的话也可以自己制作。欢迎各位在评论区分享你的小书签。</p>
<hr>
<p>下面是我为个别网站定制的新书签,仅做备份:</p>
<ul>
<li>从移动版网页跳转电脑版:<a href='javascript:(function(){ if (location.href.indexOf("m.douban") == -1) { location.href = location.href.replace("m.douban", "www.douban"); } })();'>m->www</a></li>
<li>查询狗东某图书的豆瓣评分:<a href='javascript:(function(){ var name = document.querySelector("#name > div.sku-name").textContent.replace(/\s+/g,""); url = encodeURI("https://book.douban.com/subject_search?search_text="+name); window.open(url) })();'>jd->book</a></li>
<li>在 Spotify 打开 <a href="https://1001albumsgenerator.com/">1001 Albums Generator</a> 页面推荐的专辑:<a href='javascript: (function() {location.href = "https://open.spotify.com/album/" + document.querySelector("#current-album-wrapper > div.streaming-wrapper > a.stream-spotify").href.split(":")[2];})();'>Open in Spotify</a></li>
</ul>
Laravel实用技巧
https://acuario.xyz/posts/some-skills-in-laravel/
2023-09-27T18:25:39+00:00
2019-10-31T23:43:40+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>Laravel 作为大名鼎鼎的 PHP Web 框架,有着「过度设计」的美誉(滑稽)。也就免不了附带着一些需要学习和摸索才能掌握的奇技淫巧(好吧其实只需要看看文档就行)。笔者结合自身的开发经验,把值得一提的东西梳理成文,便于读者在使用 Laravel 进行开发时事半功倍。</p>……
<p>Laravel 作为大名鼎鼎的 PHP Web 框架,有着「过度设计」的美誉(滑稽)。也就免不了附带着一些需要学习和摸索才能掌握的奇技淫巧(好吧其实只需要看看文档就行)。笔者结合自身的开发经验,把值得一提的东西梳理成文,便于读者在使用 Laravel 进行开发时事半功倍。</p>
<h2 id="composer">Composer</h2>
<p>已经 9102 年了,Composer 作为 PHP 的包管理工具,相信已经不需要做介绍了。使用 Laravel 的过程中不可避免地会使用到各种各样的第三方包,Laravel 毫无疑问是使用 Composer 进行包管理的,对于国内开发者而言,第一件事显然是把 Composer 换为国内源,只需执行一下命令即可修改全局设置:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ composer config -g repo.packagist composer https://packagist.phpcomposer.com
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="调试代码">调试代码</h2>
<h3 id="打印变量">打印变量</h3>
<p>一般使用框架自带的 <code>dd()</code> 方法而不是 PHP 原生方法 <code>print_r()</code> 或 <code>var_dump()</code> 来打印变量信息,因为 <code>dd()</code> 方法可以打印多个任何类型变量:<code>dd($object, 123, [123, 324]);</code></p>
<p>顺便一提,所谓 <em>dd</em> 的意思是 <strong>dump, die</strong>,而在最新的 Laravel 6 框架中,新增了 <code>ddd()</code> 方法,它是 <code>dd()</code> 方法的升级版,意思是 <strong>dump, die, debug</strong>,你可以在<a href="https://flareapp.io/blog/1-introducing-ddd-a-new-global-helper-for-laravel">这篇文章</a>查看该方法的介绍。</p>
<h3 id="打印-sql-语句">打印 SQL 语句</h3>
<p>在使用框架的 ORM 查询构造器时,可以通过 <code>toSql()</code> 方法输出原生 SQL 语句。</p>
<p>SQL 语句中的参数值由于被 <code>?</code> 代替,可以使用 <code>getBindings()</code> 输出构造器中的查询条件:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$builder</span> <span class="o">=</span> <span class="nx">DB</span><span class="o">::</span><span class="na">table</span><span class="p">(</span><span class="s1">'user'</span><span class="p">)</span><span class="o">-></span><span class="na">where</span><span class="p">(</span><span class="s1">'id'</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$bindings</span> <span class="o">=</span> <span class="nv">$builder</span><span class="o">-></span><span class="na">getBindings</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$sql</span> <span class="o">=</span> <span class="nx">str_replace</span><span class="p">(</span><span class="s1">'?'</span><span class="p">,</span> <span class="s1">'%s'</span><span class="p">,</span> <span class="nv">$builder</span><span class="o">-></span><span class="na">toSql</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="nv">$sql</span> <span class="o">=</span> <span class="nx">sprintf</span><span class="p">(</span><span class="nv">$sql</span><span class="p">,</span> <span class="o">...</span><span class="nv">$bindings</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">dd</span><span class="p">(</span><span class="nv">$sql</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="数据库">数据库</h2>
<h3 id="数据库迁移">数据库迁移</h3>
<p>参考文档:<a href="https://learnku.com/index.php/docs/laravel/6.x/migrations/5173">数据库迁移</a></p>
<p>Laravel 提供了一整套的数据库迁移方案,便于开发使用代码直接创建、修改数据库的表结构,而无需繁琐地书写表结构的 SQL 语句。首先使用如下命令生成迁移文件:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ php artisan make:migration do_some_migration
</span></span></code></pre></td></tr></table>
</div>
</div><p>然后在 <code>/database/migrations/</code> 目录下找到对应的迁移文件 <code>2019_08_29_172043_do_some_migration.php</code>,根据业务需求设计表结构:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Facades\Schema</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Schema\Blueprint</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Migrations\Migration</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DoSomeMigration</span> <span class="k">extends</span> <span class="nx">Migration</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * Run the migrations.
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @return void
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">up</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 创建user表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">Schema</span><span class="o">::</span><span class="na">create</span><span class="p">(</span><span class="s1">'user'</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nx">Blueprint</span> <span class="nv">$table</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$table</span><span class="o">-></span><span class="na">increments</span><span class="p">(</span><span class="s1">'id'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$table</span><span class="o">-></span><span class="na">timestamps</span><span class="p">();</span> <span class="c1">// 创建生成时间和修改时间字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nv">$table</span><span class="o">-></span><span class="na">softDeletes</span><span class="p">();</span> <span class="c1">// 创建软删除字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// 修改post表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">Schema</span><span class="o">::</span><span class="na">table</span><span class="p">(</span><span class="s1">'post'</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nx">Blueprint</span> <span class="nv">$table</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$table</span><span class="o">-></span><span class="na">uuid</span><span class="p">(</span><span class="s1">'user_id'</span><span class="p">)</span><span class="o">-></span><span class="na">after</span><span class="p">(</span><span class="s1">'id'</span><span class="p">)</span><span class="o">-></span><span class="na">comment</span><span class="p">(</span><span class="s1">'外键关联模型'</span><span class="p">);</span> <span class="c1">// 新增字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nv">$table</span><span class="o">-></span><span class="na">string</span><span class="p">(</span><span class="s1">'name'</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span><span class="o">-></span><span class="na">change</span><span class="p">();</span> <span class="c1">// 修改字段属性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nv">$table</span><span class="o">-></span><span class="na">renameColumn</span><span class="p">(</span><span class="s1">'from'</span><span class="p">,</span> <span class="s1">'to'</span><span class="p">);</span> <span class="c1">// 字段重命名
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nv">$table</span><span class="o">-></span><span class="na">dropColumn</span><span class="p">(</span><span class="s1">'votes'</span><span class="p">);</span> <span class="c1">// 删除字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * Reverse the migrations.
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @return void
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">down</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">Schema</span><span class="o">::</span><span class="na">dropIfExists</span><span class="p">(</span><span class="s1">'user'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>完成表结构设计之后执行如下命令进行数据库迁移,如果数据库配置无误的话,框架会按照迁移文件自动创建、修改表结构,完成数据库迁移操作:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ php artisan migrate // 完成所有未执行的迁移
</span></span><span class="line"><span class="cl">$ php artisan migrate --force // 强制执行迁移
</span></span><span class="line"><span class="cl">$ php artisan migrate:rollback // 回滚所有迁移
</span></span><span class="line"><span class="cl">$ php artisan migrate:refresh // 回滚所有迁移,并重新执行所有迁移,相当于重建数据库
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="数据库填充">数据库填充</h3>
<p>参考文档:<a href="https://learnku.com/index.php/docs/laravel/6.x/seeding/5174">数据填充</a></p>
<p>后端开发最头疼的就是模拟数据了,特别是新建数据库以后还要一条一条记录手动 mock 那就太糟心了。Laravel 自带了一个数据库填充引擎,可以按照工厂填空类进行数据库填充测试数据。这里分三步走战略:</p>
<ol>
<li>准备对应模型类和数据填充工厂类</li>
<li>生成数据填充执行类</li>
<li>执行填充</li>
</ol>
<h4 id="准备类文件">准备类文件</h4>
<p>创建工厂类之前你务必要先准备好对应的 <code>User</code> 模型,在本例中,<code>User</code> 模型文件位于 <code>/app/User.php</code>,然后创建工厂类 <code>/database/factories/UserFactory.php</code> ,并为每个字段写好数据填充要求:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Support\Str</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Faker\Generator</span> <span class="k">as</span> <span class="nx">Faker</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$factory</span><span class="o">-></span><span class="na">define</span><span class="p">(</span><span class="nx">App\User</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nx">Faker</span> <span class="nv">$faker</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'name'</span> <span class="o">=></span> <span class="nv">$faker</span><span class="o">-></span><span class="na">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'email'</span> <span class="o">=></span> <span class="nv">$faker</span><span class="o">-></span><span class="na">unique</span><span class="p">()</span><span class="o">-></span><span class="na">safeEmail</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'email_verified_at'</span> <span class="o">=></span> <span class="nx">now</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'password'</span> <span class="o">=></span> <span class="s1">'$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm'</span><span class="p">,</span> <span class="c1">// secret
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="s1">'remember_token'</span> <span class="o">=></span> <span class="nx">Str</span><span class="o">::</span><span class="na">random</span><span class="p">(</span><span class="mi">10</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="生成填充执行类">生成填充执行类</h4>
<p>使用如下命令生成填充执行类文件:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ php artisan make:seeder UserTableSeeder
</span></span></code></pre></td></tr></table>
</div>
</div><p>修改 <code>/database/seeds/UserTableSeeder.php</code> 文件,约束填充的记录条数:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Seeder</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserTableSeeder</span> <span class="k">extends</span> <span class="nx">CommonSeeder</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * Run the database seeds.
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @return void
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">run</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="nv">$createdAt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">//单独插入一条数据
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">App\User</span><span class="o">::</span><span class="na">insert</span><span class="p">([</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'id'</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'name'</span> <span class="o">=></span> <span class="s1">'admin'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'password'</span> <span class="o">=></span> <span class="nx">sha1</span><span class="p">(</span><span class="s1">'ooxxooxx'</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'email'</span> <span class="o">=></span> <span class="s1">''</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'remember_token'</span> <span class="o">=></span> <span class="nx">str_random</span><span class="p">(</span><span class="mi">60</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'created_at'</span> <span class="o">=></span> <span class="nv">$createdAt</span> <span class="o">?:</span> <span class="nv">$createAt</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">randDate</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'updated_at'</span> <span class="o">=></span> <span class="nv">$createdAt</span> <span class="o">?:</span> <span class="nv">$createdAt</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">randDate</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">//生成 4 个用户
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">factory</span><span class="p">(</span><span class="nx">App\User</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span><span class="o">-></span><span class="na">create</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>并在 <code>/database/seeds/DatabaseSeeder.php</code> 从添加需要填充的类文件:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Seeder</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DatabaseSeeder</span> <span class="k">extends</span> <span class="nx">Seeder</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * Run the database seeds.
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @return void
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">run</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">call</span><span class="p">([</span>
</span></span><span class="line"><span class="cl"> <span class="nx">PostTableSeeder</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">UserTableSeeder</span><span class="o">::</span><span class="na">class</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">]);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="执行填充">执行填充</h4>
<p>执行数据库填充命令收货一堆假数据:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ php artisan db:seed // 执行 DatabaseSeeder.php 内定义的所有数据库填充
</span></span><span class="line"><span class="cl">$ php artisan db:seed --class<span class="o">=</span>ExampleTableSeeder // 执行指定填充类的数据填充
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="伪造数据">伪造数据</h3>
<p>可以看到上述填充类中使用了 <code>$faker</code> 这个玩意儿,其对应的是一个可堪使用的数据填充工具 <a href="https://github.com/fzaninotto/Faker">Faker</a>,提供了诸如电话号码、地址、邮箱、用户名、文章标题、文章摘要、文章内容、图片链接等一系列的填充项,基本能够覆盖大部分需求。关于中文数据填充的相关操作可以阅读《<a href="https://blog.csdn.net/luyaran/article/details/74732423">使用 Laravel 数据填充功能生成中文测试数据</a>》</p>
<p>另外,框架自带的 <code>Illuminate\Support\Str</code> 也提供了很多丰富的字符串处理方法可堪使用。</p>
<h3 id="查询构造器">查询构造器</h3>
<p>参考文档:<a href="https://learnku.com/index.php/docs/laravel/6.x/queries/5171">查询构造器</a></p>
<p>这部分没太多可说的,掌握基本的 <code>select()</code>、<code>where()</code>、<code>whereIn()</code>、<code>group()</code>、<code>latest()</code>、<code>get()</code>、<code>paginate()</code> 基本可以完成 80% 的工作了,需要提到的是,由于查询构造器的查询方法返回值不同,这里需要格外注意:</p>
<ul>
<li><code>find($id)</code> 需要一个 id 并返回一个模型。如果不存在匹配的模型,则返回 <code>null</code>。</li>
<li><code>findOrFail($id)</code> 需要一个 id 并返回一个模型。如果不存在匹配的模型,则会引发错误,它会抛出一个 <code>error</code>。</li>
<li><code>first()</code> 返回在数据库中找到的第一条记录。如果不存在匹配的模型,则返回 <code>null</code>。</li>
<li><code>firstOrFail()</code> 返回在数据库中找到的第一条记录。如果不存在匹配的模型,则会引发错误。它会抛出一个 <code>error</code>。</li>
</ul>
<h2 id="eloquent-orm">Eloquent ORM</h2>
<h3 id="模型">模型</h3>
<p>参考文档:<a href="https://learnku.com/index.php/docs/laravel/6.x/eloquent/5176">查询构造器</a></p>
<p>在定义模型时,有两个模型类属性比较重要:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">protected</span> <span class="nv">$guarded</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'id'</span><span class="p">,</span> <span class="s1">'deleted_at'</span><span class="p">];</span> <span class="c1">//不可批量更新字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">protected</span> <span class="nv">$hidden</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'deleted_at'</span><span class="p">];</span> <span class="c1">//查询时不可见字段
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>上述字段可以视为<strong>黑名单</strong>属性,对应的<strong>白名单</strong>属性为:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">protected</span> <span class="nv">$fillable</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'name'</span><span class="p">];</span> <span class="c1">//可批量更新字段
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">protected</span> <span class="nv">$visible</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'tag'</span><span class="p">];</span> <span class="c1">//查询时可见字段
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="软删除">软删除</h3>
<p>相关操作参见:<a href="https://laravelacademy.org/post/1020.html">Eloquent ORM 实例教程 —— 模型删除及软删除相关实现</a></p>
<p>某些表字段设计为软删除,而非物理删除,在模型内使用软删除,只需两步:</p>
<ol>
<li>引用软删除 trait</li>
<li>增加软删除字段</li>
</ol>
<h4 id="引用软删除-trait">引用软删除 Trait</h4>
<p>首先在目标模型上使用 <code>Illuminate\Database\Eloquent\SoftDeletes</code> trait:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\Model</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\SoftDeletes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Flight</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">use</span> <span class="nx">SoftDeletes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="增加软删除字段">增加软删除字段</h4>
<p>这一部分不再赘述,可以参照前文数据库迁移部分,新增一个软删除字段,默认新增的软删除字段名为 <code>deleted_at</code>。</p>
<p>你也可以手动修改数据库表结构增加自定义名称的软删除字段,当然,你需要在对应的模型中使用 <code>DELETED_AT</code> 类常量指定自定义的软删除字段名:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">App</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\Model</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\SoftDeletes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Flight</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">use</span> <span class="nx">SoftDeletes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="no">DELETED_AT</span> <span class="o">=</span> <span class="s1">'custom_delete_colunm'</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="其他说明">其他说明</h4>
<p>一般来说,完成前述设置后已经可以正常使用软删除,当你在模型实例上使用 <code>delete()</code> 方法删除数据实例时,当前日期时间会写入 <code>deleted_at</code> 字段,表示该记录被软删除。同时,查询出来的结果也会自动排除已被软删除的记录。</p>
<p>需要硬删除的话使用 <code>forceDelete()</code> 方法即可。</p>
<p>为了使模型定义更加清晰,不妨在目标模型内设置类成员变量,显式指定 <code>deleted_at</code> 字段的类型:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">protected</span> <span class="nv">$dates</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'deleted_at'</span><span class="p">];</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>当然,如果你不想将该字段的值设为删除日期,也可以对其进行改造,具体改造方式可以参阅《<a href="http://blog.dreamlikes.cn/archives/892">Laravel5软删除(SoftDeletes)的deleted_at改造</a>》</p>
<h3 id="修改器">修改器</h3>
<p>对数据库字段的特殊处理,可以使用 <a href="https://learnku.com/docs/laravel/5.7/eloquent-mutators/2297">Eloquent 修改器</a> 对入库字段进行预处理,比如姓名首字母大写才能入库等等。</p>
<p>另外,某字段储存为 json 格式,处理时需要转换为 PHP 数组,也只需在模型内声明 <code>$cast</code> 属性加入 array 类型转换,当你访问的时候就会自动被转换为 PHP 数组:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">protected</span> <span class="nv">$casts</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'options'</span> <span class="o">=></span> <span class="s1">'array'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="游标">游标</h3>
<p><code>cursor</code> 方法允许你使用游标遍历数据库,它只执行一次查询。处理大量的数据时, <code>cursor()</code> 方法可以大大减少内存的使用量,比如导入、导出数据时,如果直接 <code>foreach</code> 遍历变量,可能会犹豫变量太大导致内存溢出。此事使用基于迭代器的游标可以大大提升程序的鲁棒性:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nx">Flight</span><span class="o">::</span><span class="na">where</span><span class="p">(</span><span class="s1">'foo'</span><span class="p">,</span> <span class="s1">'bar'</span><span class="p">)</span><span class="o">-></span><span class="na">cursor</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$flight</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="关联模型">关联模型</h3>
<p>参考文档:<a href="https://learnku.com/index.php/docs/laravel/6.x/eloquent-relationships/5177">关联模型</a></p>
<p>这一部分可以说是 Laravel 的精髓所在。框架设计的模型关联可以将多个模型之间的关联关系在 Model 中定义清楚,便于数据查询和后期维护,特别是在例如列表页、详情页等需求中轻松地获取有关联关系的将数据对象,完全无需自己手动拼接、处理数据。</p>
<p>举两个例子:</p>
<ul>
<li>
<p>在 User 和 Post 模型中绑定关联关系后,就可以使用 <code>$post->comments</code> 来获取该文章对应的全部评论。</p>
</li>
<li>
<p>在列表查询时,可能需要减少多次查询,避免 <code>1+N</code> 次查询。比如文章列表:</p>
<ol>
<li>获取文章</li>
<li>获取每篇文章的评论</li>
</ol>
</li>
</ul>
<p>ps. 数据库中文章表为 <code>post</code>,评论表为 <code>comment</code></p>
<p>如果遍历 <code>$posts</code> 使用关联查询 <code>$post->comments</code> 将造成过多不必要的 SQL 查询。假设该页有 10 条 post 记录,正常情况将执行 <code>1+10=11</code> 条 SQL。为解决这种多查询问题,可以使用<a href="https://learnku.com/docs/laravel/5.8/eloquent-relationships/3932#eager-loading">预加载</a>来实现最简查询。</p>
<p>使用时,在查询语句中使用 <code>with()</code> 即可,如:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$books</span> <span class="o">=</span> <span class="nx">App\Book</span><span class="o">::</span><span class="na">with</span><span class="p">(</span><span class="s1">'author'</span><span class="p">)</span><span class="o">-></span><span class="na">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$books</span> <span class="k">as</span> <span class="nv">$book</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">echo</span> <span class="nv">$book</span><span class="o">-></span><span class="na">author</span><span class="o">-></span><span class="na">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>获取关联对象的数量可以使用<a href="https://learnku.com/docs/laravel/5.8/eloquent-relationships/3932#counting-related-models">关联模型计数</a> 的 <code>withCount()</code> 方法,它将放在结果模型的 <code>{relation}_count</code> 列,如:</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$posts</span> <span class="o">=</span> <span class="nx">App\Post</span><span class="o">::</span><span class="na">withCount</span><span class="p">(</span><span class="s1">'comments'</span><span class="p">)</span><span class="o">-></span><span class="na">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$posts</span> <span class="k">as</span> <span class="nv">$post</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">echo</span> <span class="nv">$post</span><span class="o">-></span><span class="na">comments_count</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="跨域">跨域</h2>
<p>处理跨域问题可以考虑使用 <a href="https://xueyuanjun.com/post/9273.html">Laravel CORS 扩展包</a></p>
<hr>
<p>暂时就写这么多,上述技巧基本可以涵盖常见的 CURD 需求(滑稽。如果你有其他推荐的奇技淫巧不妨在评论区留言。</p>
播客札记(四):消费主义&审美
https://acuario.xyz/others/podcast-note-4/
2023-09-27T18:25:39+00:00
2019-09-16T01:29:19+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="翻转问答-vol30--道理能解决消费主义和奢侈的否定欲望">翻转问答 VOL30 | 道理能解决消费主义和奢侈的否定欲望?</h2>
<p><a href="https://podtail.com/podcast/%E7%BF%BB%E8%BD%AC%E7%94%B5%E5%8F%B0flip-radio/--30/">Episode Archive</a></p>
<h3 id="道理无法解决问题">道理无法解决问题</h3>
<ul>
<li>消费主义本身并不是一个多深的批判,对消费主义的批评不需要过高的学术门槛。</li>
<li>批判难度低并不意味着不具备批判价值。</li>
<li>掌握道理本身不难,但改变和解决问题并不能通过了解某个道理来完成。</li>
</ul>……
<h2 id="翻转问答-vol30--道理能解决消费主义和奢侈的否定欲望">翻转问答 VOL30 | 道理能解决消费主义和奢侈的否定欲望?</h2>
<p><a href="https://podtail.com/podcast/%E7%BF%BB%E8%BD%AC%E7%94%B5%E5%8F%B0flip-radio/--30/">Episode Archive</a></p>
<h3 id="道理无法解决问题">道理无法解决问题</h3>
<ul>
<li>消费主义本身并不是一个多深的批判,对消费主义的批评不需要过高的学术门槛。</li>
<li>批判难度低并不意味着不具备批判价值。</li>
<li>掌握道理本身不难,但改变和解决问题并不能通过了解某个道理来完成。</li>
</ul>
<h3 id="个人主义与消费依存">个人主义与消费依存</h3>
<ul>
<li>消费主义与消费不是一回事。</li>
<li>个人主义兴起之后,社会分工的消费交换使消费主义与消费的关联越来越紧密。</li>
<li>依靠消费来维持日常生活,并不一定是消费主义的,而「由单一消费提供一切」的生活就是消费主义的。举例来说,购买器材录制播客,在录制过程中产出的内容并不是消费行为本身能够购买而来的,所以这一行为本身不是消费主义的。简单来看,消费过程中是否有内容产出,可以视为判断是否是消费主义的一个依据。</li>
</ul>
<h3 id="平民主义与消费权的平等">平民主义与消费权的平等</h3>
<ul>
<li>消费权的平等伴随这消费门槛的降低而逐渐消失。在过去,某些消费具有门槛,例如衣冠不整不可进入餐厅;贵族社会使用的产品为特供等。</li>
<li>消费权的不平等意味着在既有时代背景下,消费作为一种客体并不是最重要的东西,而导致消费不平等的因素或许比消费更重要,例如前述例子中的文明程度、权力等。</li>
<li>平民主义兴起使得导致消费权不平等的因素越来越被反对,导致消费权不平等的各种特权亦被排斥,进而消逝。例如,一辆好车应该卖给谁,不以驾驶技术高低而论,而是价高者得。</li>
<li>在诉诸消费权平等的过程中,金钱逐渐成为了决定消费的最重要的要素。附着在消费行为上的其他价值被渐渐瓦解,消费内涵的价值成了钱的价值。</li>
<li>追求钱的价值会让物质的使用意义逐渐消逝,成为被观看的现象,让<strong>社会景观化</strong>。</li>
<li>物质本身的使用价值,需要更多的公共场合来展示,需要更多的公众关注。公共场合越小,公共场合越萎缩,社会越景观化,社会就越容易进入消费主义。</li>
</ul>
<h3 id="奢侈的问题">奢侈的问题</h3>
<ul>
<li>消费社会和消费品不仅提供了某种视觉表象,对于使用者而言还展示某种不必要的奢侈体验。其背后有强烈的「由俭入奢易,由奢入俭难」效应。抖音在互联网时代带给人廉价甚至无物质成本的奢侈体验,带给人高频率的精神刺激,这是任何文艺作品无法提供的。</li>
<li>消费主义自身提供了特别自洽的体系,当人进入消费主义之后,真正的阻碍只有是自身经济和金钱的成长。买的越多,则愈加排除传统价值,而消费主义又可在此过程中提供充足的合理化说辞,让人满足于符号消费和消费主义本身,从而维持一个「快乐的生活」,在现代社会下,「快乐生活」更容易被看到,也导致了对个体自身更多的正向反馈。</li>
</ul>
<h3 id="人必然会选择消费主义吗">人必然会选择消费主义吗</h3>
<ul>
<li>人的满足是边际效益递减的,这要求人的消费越来越多,越来越快。这和资本主义的生产力过剩不谋而合。从方方面面来看,消费主义都符合现代社会的特征。</li>
</ul>
<h3 id="生的肯定的创造的欲望与死的否定的消费的欲望">生的,肯定的,创造的欲望与死的,否定的,消费的欲望</h3>
<ul>
<li>巴塔耶的耗费经济学认为,消费是一种浪费(waste),消费具有强烈的「浪费」和「毁灭」的欲望的。现代社会对多媒体作品的消费,根本上算是一种浪费和毁灭。其他领域的消费也包含巨大的浪费、过剩和毁灭的意味。</li>
<li>巴塔耶普遍经济学的意图就是把衰败的世界与人的内在生命、主观经验协调一致。这有死的世界,他认为是物质性的、普遍的能量之流,不停顿地要求消耗和散失,最终意味着我们能累积起来的资源的完全毁灭。</li>
<li>消费主义本身是一种强烈的否定的、死的欲望,无论对于物品还是自己,消费主义强调的是浪费、毁灭、自我的物化、自我的非人化;其反面是生的欲望,强调的是自我独特性、强调生存、强调自我肯定,它导向的是创造行为而非消费行为,这与规模化的商品生产和直接获取他人商品背道而驰。</li>
<li>死的欲望不是在生理上杀死人,而是在精神上让人不是「人」。在消费主义内部,有强烈的让人不是人的冲动。这种冲动一方面来自经济系统本身——它需要人通过这种浪费的、标准化的消费来否定自己,也是人在资本主义背景下的自我选择。</li>
<li>整个城市的分工生活,是所有「奢侈」的集合。「奢侈」选择包含着否定的、死的欲望,过多的「奢侈」选择会阻碍人作为人的发展,让人进入非人化的状态。</li>
</ul>
<h3 id="消费主义不是死局">消费主义不是死局</h3>
<ul>
<li>消费主义真正控制我们的三个要素:
<ul>
<li>奢侈快感</li>
<li>对社会景观的依赖</li>
<li>奢侈与背后的一套概念</li>
</ul>
</li>
<li>从任何角度对消费主义「控制三要素」的回击,都是自我生活和个体发展尝试脱离消费主义的有效途径。</li>
<li>消费主义不是非此即彼,例如看电影行为本身是消费主义,但如果能留下对电影本身的任何创造性内容,那看电影本身就不再是消费主义行为。</li>
<li>消费主义和技术进步带来的便利性,有些是创造的便利性,有些是享乐和消费的便利性,但在系统内部二者并非对称关系,消费的便利性远远大于创造的便利性。即便技术的发展让人的创造成本大大降低,但实际上人的享乐成本被降低得更多。</li>
<li>考虑反对消费主义的消费选择,可以从消费本身的创造性可能来进行衡量。</li>
<li>西方的思想(古希腊)认为「知道」就是美德,而东方的思想(印度)认为践行才是美德,人不可能通过对道理的思考和理解来改变生活,而需要切身实践。</li>
<li>消费主义不是死局,切实可行的建议是,为了与你有关系的人,创作个什么东西,一顿佳肴,一篇文章,一幅画,什么都行</li>
</ul>
<hr>
<h2 id="翻电问答-vol21--美的丧失与美的教育">翻电问答 VOL21 | 美的丧失与美的教育</h2>
<p><a href="https://podtail.com/podcast/%E7%BF%BB%E8%BD%AC%E7%94%B5%E5%8F%B0flip-radio/%E7%BF%BB%E7%94%B5%E9%97%AE%E7%AD%94-21-%E7%BE%8E%E7%9A%84%E4%B8%A7%E5%A4%B1%E4%B8%8E%E7%BE%8E%E7%9A%84%E6%95%99%E8%82%B2/">Episode Archive</a></p>
<ul>
<li>批评美丑前,需要对自我生活的文化选择和评价进行审视和思考。</li>
<li>对美丑的批判难以取得共识,而相对容易获得共识的批判一般出现在公权力介入的美丑批判中,如商店的标牌规范、公共建筑规范。</li>
<li>如今对艺术作品的评价,多用一个哲学框架进行分析,而非进行美和丑的简单判断,批判的难度并不低。但另一方面,人们又乐于进行审美评判。</li>
</ul>
<h3 id="美与丑的界限是模糊的么">美与丑的界限是模糊的么?</h3>
<ul>
<li>导致批判美丑变为难以进行的话题的一大原因是大众认为「美与丑的界限是模糊的」。</li>
<li>对善恶、美丑的讨论容易陷入复杂论的视角,即认为讨论的主体是不可轻易判断、得出结论的。亦容易产生明显的主客二元论想法,认为「美丑是个主观的东西」。「____是主观的」一类防守性言论也容易让人服从于达成共识的压力,产生难以达成共识的思维惯性,阻碍沟通与思考。</li>
<li>康德在《判断力批判》中认为,美是一种先验综合,虽然美是主观判断,但并不是不可讨论之物:</li>
</ul>
<blockquote>
<p>一个对象,一束美丽的花,引起了我们的情感,而这种情感呢,我认为它是有普遍性的,我把这种情感叫做 “美”。我相信人人看到这朵花都会觉得美,都会有这种情感。具体的东西里有普遍性,不需要你带来一个概念加在它的上面,去规定它,它自己就表现出某种普遍性了。就是说,这朵花,它可以引起每一个人的美感,这种美感是有普遍性的。那么,“这朵花是美的”,这个判断与 “这朵花是植物”,或者 “这朵花是红的” 这样的判断,是大不一样的。——<a href="https://zhuanlan.zhihu.com/p/23421249">邓晓芒:康德的《判断力批判》主要在讲什么?</a></p>
</blockquote>
<ul>
<li>「美」是高度词义弱化和异化的词汇,导致对美的讨论难以进行:
<ul>
<li>美的生理学基础中,最常被讨论的是性冲动与审美的关系——这是人际关系劣化的的结果,认为人与人的关系变为生理性要素占主导地位,但这样动物性的视角在谈论美的时候过于狭隘。</li>
<li>科学主义的劣化途径使得「美」更易被量化,易于得出基于数据的结果,能够形成具有统计学意义的实验。让人产生「美」具有建构性特点的错觉,并将美视为与先验无关,并无实质基础的社会文化综合产物。</li>
</ul>
</li>
</ul>
<h3 id="美育可以解决美的问题么">美育可以解决美的问题么?</h3>
<ul>
<li>生活中接受美与丑的门槛都是相同的,个体审美能力的缺失在于忽视美的存在,而非商业或政治的责任。</li>
<li>对美育的痴迷并不能解决人最根本的审美问题。教育万能论的思维导向让人认为美育能够改变人的审美能力,但实际上,文化教育不能让人有文化,美育教育亦不能让人有审美。</li>
<li>教育只能给人知识,让人了解知识、掌握技术和逻辑推理,但无法让人获得审美能力,因为「美」是直觉判断的能力而非外部学习的存在。</li>
</ul>
<h3 id="审美是一种技能和能力吗">审美是一种技能和能力吗?</h3>
<ul>
<li>审美是人在成长过程中逐渐唤醒的判断力。它在儿时以潜能的方式蕴藏于体内,因此是先验的,这个潜能在综合的不断判断之中慢慢唤起。正如荣格所认为的那样,人在儿时并不具有纯真、美好的品质,人在出生时什么都没有,这些潜能随着人的逐渐长大生发出来,才慢慢出现了这些品质。</li>
</ul>
<h3 id="美的-缺失-就是-拒绝长大">美的 “缺失” 就是 “拒绝长大”</h3>
<ul>
<li>对「美」本身的否定,一方面否定了成长给人带来的差异,「拒绝长大」没,否定了成长带来品质的改变;另一方面拒绝了当下所处环境的恶劣,拒绝了充斥着丑恶的生存空间。</li>
<li>当今社会相对单一的审美判断,使得人们普遍不认为成长应该视为获得美的途径,从而过分看重「成长」之外的东西,例如财富、地位、资源。</li>
<li>美是一个责任——人的决断要求人以某种特定判断力作为标准,而非儿时的生理快感作为判断力标准。获得以美作为标准的判断力需要承担的最大责任是「相信」,相信美感需要的是决断、专注和对自我的承诺。放弃对美的信任,就可以随波逐流,让美流失。</li>
<li>一切以消费、逃避的心态对待美都是不可能获得美的。</li>
</ul>
《Modern PHP》学习笔记
https://acuario.xyz/posts/modern-php-summary/
2023-09-27T18:25:39+00:00
2019-08-24T16:33:23+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="命名空间namespace">命名空间(namespace)</h2>
<h3 id="基本概念">基本概念</h3>
<ul>
<li>PHP 命名空间与操作系统的物理文件系统不同,这是一个虚拟概念,没必要和文件系统中的目录结构完全对应。但是大多数 PHP 组件为了兼容 PSR-4 自动加载器标准,会把子命名空间放到文件系统的子目录中。</li>
<li>从技术层面来看,命名空间只是 PHP 语言中的一种记号,PHP 解释器会将其作为前缀添加到类、接口、函数和常量的名称前面。</li>
<li>不同代码可能使用相同的类名、接口名、函数名或常量名,如果不使用命名空间,名称会起冲突,导致 PHP 执行出错。而使用命名空间,把代码放在唯一的厂商命名空间中,这样不同命名空间下的代码就可以使用相同的名称命名类、接口、函数和常量。</li>
<li>在同一个命名空间或子命名空间中的所有类没必要在同一个 PHP 文件中声明。你可以在 PHP 文件的顶部指定一个命名空间或子命名空间,此时,这个文件中的代码就是该命名空间或子命名空间的一部分。因此,我们可以在不同的文件中编写属于同一个命名空间的多个类。</li>
</ul>……
<h2 id="命名空间namespace">命名空间(namespace)</h2>
<h3 id="基本概念">基本概念</h3>
<ul>
<li>PHP 命名空间与操作系统的物理文件系统不同,这是一个虚拟概念,没必要和文件系统中的目录结构完全对应。但是大多数 PHP 组件为了兼容 PSR-4 自动加载器标准,会把子命名空间放到文件系统的子目录中。</li>
<li>从技术层面来看,命名空间只是 PHP 语言中的一种记号,PHP 解释器会将其作为前缀添加到类、接口、函数和常量的名称前面。</li>
<li>不同代码可能使用相同的类名、接口名、函数名或常量名,如果不使用命名空间,名称会起冲突,导致 PHP 执行出错。而使用命名空间,把代码放在唯一的厂商命名空间中,这样不同命名空间下的代码就可以使用相同的名称命名类、接口、函数和常量。</li>
<li>在同一个命名空间或子命名空间中的所有类没必要在同一个 PHP 文件中声明。你可以在 PHP 文件的顶部指定一个命名空间或子命名空间,此时,这个文件中的代码就是该命名空间或子命名空间的一部分。因此,我们可以在不同的文件中编写属于同一个命名空间的多个类。</li>
</ul>
<h3 id="导入和别名">导入和别名</h3>
<ul>
<li><strong>导入</strong>是指在每个 PHP 文件中告诉 PHP 想使用哪个命名空间、类、接口、函数和常量。导入后就不用输入全名了。</li>
<li><strong>创建别名</strong>是指告诉 PHP 我要使用简单的名称引用导入的类、接口、函数或常量。</li>
<li>使用 <code>use</code> 关键字导入代码时无需在开头加上符号,因为 PHP 假定导入的是<strong>完全限定</strong>的命名空间。</li>
<li><code>use</code> 关键字必须出现在<strong>全局作用域</strong>中(即不能在类或函数中),因为这个关键字在编译时使用。不过,use 关键字可以在命名空间声明语句之后使用,导入其他命名空间中的代码。</li>
<li>导入函数和常量:</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">func</span> <span class="k">Namespace</span><span class="nx">\functionName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">constant</span> <span class="k">Namespace</span><span class="nx">\CONST_NAME</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">functionName</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">CONST_NAME</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><strong>一个文件定义一个类</strong>,一个文件只使用一个命名空间。</li>
<li>有些代码可能没有命名空间,这些代码在全局命名空间中。如果需要在命名空间中引用其他命名空间中的类、接口、函数或常量,必须使用完全限定的 PHP 类名(命名空间类名)。在命名空间中引用全局命名空间中的代码时,要在类、接口、函数或常量的名称前加上 <code>\</code> 符号。</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">My\App</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">Class</span> <span class="nc">Foo</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">dosomething</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$exception1</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Exception</span><span class="p">();</span> <span class="c1">// \My\App\Exception 类中搜索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nv">$exception2</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\Exception</span><span class="p">();</span> <span class="c1">// PHP 原生的 Exception 类
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="接口interface">接口(interface)</h2>
<ul>
<li>接口是两个 PHP 对象之间的契约,其目的不是让一个对象依赖另一个对象的身份,而是依赖另一个对象的能力。</li>
<li>接口将项目代码和依赖解耦,并允许项目代码依赖任何实现了预期接口的第三方代码而<strong>不用关心第三方代码是如何实现接口的,只关心第三方代码是否实现了指定的接口</strong>。</li>
</ul>
<p>例程(<a href="https://github.com/codeguy/modern-php/tree/master/02-features/interfaces">完整版</a>):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$documentStore</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DocumentStore</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Add HTML document
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$htmlDoc</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HtmlDocument</span><span class="p">(</span><span class="s1">'http://php.net'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$documentStore</span><span class="o">-></span><span class="na">addDocument</span><span class="p">(</span><span class="nv">$htmlDoc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Add terminal command document
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$cmdDoc</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CommandOutputDocument</span><span class="p">(</span><span class="s1">'cat /etc/hosts'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$documentStore</span><span class="o">-></span><span class="na">addDocument</span><span class="p">(</span><span class="nv">$cmdDoc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">print_r</span><span class="p">(</span><span class="nv">$documentStore</span><span class="o">-></span><span class="na">getDocuments</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DocumentStore</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="nv">$data</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">addDocument</span><span class="p">(</span><span class="nx">Documentable</span> <span class="nv">$document</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$key</span> <span class="o">=</span> <span class="nv">$document</span><span class="o">-></span><span class="na">getId</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$value</span> <span class="o">=</span> <span class="nv">$document</span><span class="o">-></span><span class="na">getContent</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">data</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getDocuments</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">interface</span> <span class="nx">Documentable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getId</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getContent</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CommandOutputDocument</span> <span class="k">implements</span> <span class="nx">Documentable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="nv">$command</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$command</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">command</span> <span class="o">=</span> <span class="nv">$command</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getId</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">command</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getContent</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">shell_exec</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">command</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">HtmlDocument</span> <span class="k">implements</span> <span class="nx">Documentable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="nv">$url</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">url</span> <span class="o">=</span> <span class="nv">$url</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getId</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">url</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getContent</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$ch</span> <span class="o">=</span> <span class="nx">curl_init</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="nx">curl_setopt</span><span class="p">(</span><span class="nv">$ch</span><span class="p">,</span> <span class="nx">CURLOPT_URL</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-></span><span class="na">url</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">curl_setopt</span><span class="p">(</span><span class="nv">$ch</span><span class="p">,</span> <span class="nx">CURLOPT_RETURNTRANSFER</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">curl_setopt</span><span class="p">(</span><span class="nv">$ch</span><span class="p">,</span> <span class="nx">CURLOPT_CONNECTTIMEOUT</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">curl_setopt</span><span class="p">(</span><span class="nv">$ch</span><span class="p">,</span> <span class="nx">CURLOPT_FOLLOWLOCATION</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">curl_setopt</span><span class="p">(</span><span class="nv">$ch</span><span class="p">,</span> <span class="nx">CURLOPT_MAXREDIRS</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$html</span> <span class="o">=</span> <span class="nx">curl_exec</span><span class="p">(</span><span class="nv">$ch</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">curl_close</span><span class="p">(</span><span class="nv">$ch</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$html</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="性状trait">性状(trait)</h2>
<ul>
<li>性状既不是类也不是接口,而是类的部分实现(即常量,属性和方法),可以混入一个或多个现有的 PHP 类中。</li>
<li>性状的作用:
<ol>
<li>表明类可以做什么(类似接口);</li>
<li>提供模块化实现(类似类)。</li>
</ol>
</li>
<li>性状能把模块化的实现方式注入多个无关的类中。而且性状还能促进代码重用。</li>
<li>使用性状的场景:
<ol>
<li>创建一个基类,然后共同集成这个基类,将共用方法写在基类中。但无关的两个类并不应集成相同的父类。</li>
<li>创建接口,然后在两个类中分别实现该接口并使用。但如果实现方法相同,则违背了 DRY(Don't Repeat Yourself)原则。</li>
</ol>
</li>
<li>与定义类和接口一样,一个文件只定义一个性状。</li>
<li>命名空间、类、接口函数和常量<strong>在类的定义体外</strong>导入,而性状<strong>在类的定义体内</strong>导入。</li>
<li>PHP 解释器在编译时会把性状复制粘贴到类的定义体中,但是<strong>不会处理这个操作引入的不兼容问題</strong>。如果性状假定类中有特定的属性或方法(在性状中没有定义),要确保相应的类中有对应的属性和方法。</li>
</ul>
<p>例程:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$adapter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\Ivory\HttpAdapter\CurlHttpAdapter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$geocoder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\Geocoder\Provider\GoogleMaps</span><span class="p">(</span><span class="nv">$adapter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$store</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">RetailStore</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$store</span><span class="o">-></span><span class="na">setAddress</span><span class="p">(</span><span class="s1">'420 9th Avenue, New York, NY 10001 USA'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$store</span><span class="o">-></span><span class="na">setGeocoder</span><span class="p">(</span><span class="nv">$geocoder</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$latitude</span> <span class="o">=</span> <span class="nv">$store</span><span class="o">-></span><span class="na">getLatitude</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$longitude</span> <span class="o">=</span> <span class="nv">$store</span><span class="o">-></span><span class="na">getLongitude</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$latitude</span><span class="p">,</span> <span class="s1">':'</span><span class="p">,</span> <span class="nv">$longitude</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">RetailStore</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">use</span> <span class="nx">TraitExample</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">//......
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">trait</span> <span class="nx">Geocodable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="sd">/** @var string */</span>
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="nv">$address</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="sd">/** @var \Geocoder\Geocoder */</span>
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="nv">$geocoder</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="sd">/** @var \Geocoder\Model\AddressCollection */</span>
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="nv">$geocoderResult</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">setGeocoder</span><span class="p">(</span><span class="nx">\Geocoder\Geocoder</span> <span class="nv">$geocoder</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">geocoder</span> <span class="o">=</span> <span class="nv">$geocoder</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">setAddress</span><span class="p">(</span><span class="nv">$address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">address</span> <span class="o">=</span> <span class="nv">$address</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getLatitude</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">geocoderResult</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">geocodeAddress</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">geocoderResult</span><span class="o">-></span><span class="na">first</span><span class="p">()</span><span class="o">-></span><span class="na">getLatitude</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">getLongitude</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">geocoderResult</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">geocodeAddress</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">geocoderResult</span><span class="o">-></span><span class="na">first</span><span class="p">()</span><span class="o">-></span><span class="na">getLongitude</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">protected</span> <span class="k">function</span> <span class="nf">geocodeAddress</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$this</span><span class="o">-></span><span class="na">geocoderResult</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">geocoder</span><span class="o">-></span><span class="na">geocode</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="生成器generator">生成器(generator)</h2>
<ul>
<li>生成器是简单的<strong>迭代器</strong>。</li>
<li>PHP 生成器不要求类实现 <code>Iterator</code> 接口,并会根据需求即时计算并产出要迭代的值,不占用宝贵的内存资源。</li>
<li>生成器是<strong>一次性的</strong>,无法多次迭代同个生成器,但可以重建或克隆生成器</li>
<li>每次产出一个值之后,生成器的内部状态都会停顿;向生成器请求下一个值时,内部状态又会恢复。生成器的内部状态会一直在停顿和恢复之间切换,直到抵达函数定义体的末尾或遇到空的 return;语句为止。</li>
<li>生成器是<strong>只能向前进的迭代器</strong>,不能使用生成器在数据集中执行后退、快进或査找操作,只能让生成器计算并产生下一个值。迭代大型数据集或数列时最适合使用生成器,因为这样占用的系统内存量极少。</li>
<li>更多技巧与实践:<a href="https://www.twitter.com/ircmaxell">@ircmaxell</a> - <a href="https://blog.ircmaxell.com/2012/07/what-generators-can-do-for-you.html">What Generators Can Do For You</a></li>
</ul>
<p>例程一:生成一个范围内的数值数组且善用内存</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">makeRange</span><span class="p">(</span><span class="nv">$length</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o"><</span> <span class="nv">$length</span><span class="p">;</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="nv">$i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nx">makeRange</span><span class="p">(</span><span class="mi">1000000</span><span class="p">)</span> <span class="k">as</span> <span class="nv">$i</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">echo</span> <span class="nv">$i</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>例程二:读取一个超过 PHP 可用内存上限的 CSV 文件。只为 CSV 文件中的一行分配内存,而不会把整个 CSV 文件都读取到内存中。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">getRows</span><span class="p">(</span><span class="nv">$file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nv">$handle</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="nv">$file</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$handle</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">throw</span> <span class="k">new</span> <span class="nx">Exception</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="nx">feof</span><span class="p">(</span><span class="nv">$handle</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="nx">fgetcsv</span><span class="p">(</span><span class="nv">$handle</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fclose</span><span class="p">(</span><span class="nv">$handle</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nx">getRows</span><span class="p">(</span><span class="s1">'data.csv'</span><span class="p">)</span> <span class="k">as</span> <span class="nv">$row</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">print_r</span><span class="p">(</span><span class="nv">$row</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="闭包closure">闭包(closure)</h2>
<ul>
<li><strong>闭包</strong>是指在创建时封装周围状态的函数。即便闭包所在的环境不存在了,闭包中封装的状态依然存在。</li>
<li><strong>匿名函数</strong>就是没有名称的函数,可以调用,还可以传入参数。</li>
<li>匿名函数<strong>可以赋值给变量</strong>,还能像对象那样传递。</li>
<li>匿名函数适合作为函数或方法的回调。</li>
<li>在 PHP 中,匿名函数 = 闭包。</li>
<li>闭包和匿名函数是<strong>伪装成函数的对象</strong>。</li>
<li>PHP 闭包不会自动封装应用的状态,必须手动调用闭包对象的 <code>bindto()</code> 方法或者使用 <code>use</code> 关键字,把状态附加到 PHP 闭包上,这样即便返回的闭包对象跳出了其函数的作用域,它也会记住参数的值,即将应用状态封装起来。</li>
<li>与任何其他 PHP 对象类似,每个闭包实例都可以使用 $this 关键字获取闭包的内部状态。<code>bindto()</code> 方法可以把 Closure 对象的内部状态绑定到其他对象上。</li>
<li>闭包可以访问绑定闭包的对象中受保护和私有的成员变量。</li>
</ul>
<p>例程一:普通闭包</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$numbersPlusOne</span> <span class="o">=</span> <span class="nx">array_map</span><span class="p">(</span><span class="k">function</span> <span class="p">(</span><span class="nv">$number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nv">$number</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">print_r</span><span class="p">(</span><span class="nv">$numbersPlusOne</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Outputs --> [2,3,4]
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>例程二:封装应用状态的闭包</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">enclosePerson</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$doCommand</span><span class="p">)</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">sprintf</span><span class="p">(</span><span class="s1">'%s, %s'</span><span class="p">,</span> <span class="nv">$name</span><span class="p">,</span> <span class="nv">$doCommand</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Enclose "Clay" string in closure
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$clay</span> <span class="o">=</span> <span class="nx">enclosePerson</span><span class="p">(</span><span class="s1">'Clay'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Invoke closure with command
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$clay</span><span class="p">(</span><span class="s1">'get me sweet tea!'</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Outputs --> "Clay, get me sweet tea!"
</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="zend-opcache">Zend OPcache</h2>
<ul>
<li>
<p>PHP 是解释型语言,PHP 解释器执行 PHP 脚本时会解析 PHP 脚本代码,把 PHP 代码编译成一系列 <a href="http://bit.ly/zend-opcode">Zend 操作码</a>,然后执行字节码。Zend OPcache 可以让 PHP 解释器从内存中读取预先编译好的字节码,然后立即执行。这样能节省很多时间,极大地提升应用的性能。</p>
</li>
<li>
<p>启用步骤:</p>
<ol>
<li>编译:<code>$ ./configure --enable-opcache</code></li>
<li>启用扩展:<code>zend_extension=/path/to/opcache.so</code></li>
<li>配置:</li>
</ol>
<pre tabindex="0"><code>opcache.validate_timestamps = 1 //检测 PHP 脚本变动。建议生产环境设为 0
opcache.revalidate_freq = 0 //检査 PHP 脚本内容变化的周期,单位秒。
opcache.memory_consumption = 64 // 为操作码缓存分配的内存量(单位是 MB)。分配的内存量应该够保存应用中所有 PHP 脚本编译得到的操作码。
opcache.interned_strings_buffer = 16 // 用来存储驻留字符串(interned string)的内存量(单位是 MB)。默认值为 4MB。
opcache.max_accelerated_files = 4000 // 操作码缓存中最多能存储多少个 PHP 脚本。
opcache.fast_shutdown = 1 // 设置操作码使用更快的停机步骤
</code></pre></li>
</ul>
<h2 id="内置的-http-服务器">内置的 HTTP 服务器</h2>
<ul>
<li>从 PHP 5.4.0 起,PHP 内置了 Web 服务器。</li>
<li>启动本地运行:<code>$ php -S localhost:4000</code></li>
<li>启动局域网访问:<code>$ php -S 0.0.0.0:4000</code></li>
<li>指定配置文件启动:<code>$ php -S localhost:8000 -c app/config/php.ini</code></li>
<li>指定路由器脚本启动:<code>$ php -S localhost:8000 router.php</code></li>
<li>内置的 HTTP 服务器仅用于本地开发调试,不应使用于生产环境。</li>
</ul>
<h2 id="标准">标准</h2>
<ul>
<li>PHP Framework Interop Group(简称 PHP-FIG,http://www.php-fig.org )。PHP-FIG 由一些 PHP 框架代表组成,PHP-FIG 制定了推荐规范,PHP 框架可以自愿实现这些规范,改进与其他框架的通信和共享功能。</li>
<li>PHP-FIG 的使命是实现框架的互操作性:通过接口、自动加载机制和标准的风格,让框架相互合作。</li>
<li>接口:框架通过 PHP 接口假定第三方依赖提供了什么方法,而不关心依赖是如何实现接口的。
<ul>
<li>自动加载:PHP 解释器在运行时按需自动找到并加载 PHP 类的过程。只需使用一个自动加载器就能混合搭配多个 PHP 组件。</li>
<li>风格:指定如何使用空格、大小写和括号的位置(等等)之类的代码格式规范。</li>
</ul>
</li>
</ul>
<h3 id="psr-1基本的代码风格">PSR-1:基本的代码风格</h3>
<ul>
<li>PHP 标签:使用 <code><?php ?></code> 或 <code><?= ?></code></li>
<li>编码:使用 <code>UTF-8</code> 编码</li>
<li>目的:一个 PHP 文件只处理一件事</li>
<li>自动加载:PHP 命名空间和类必须遵守 PSR-4 自动加载器标准</li>
<li>类的名称:PHP 类的名称必须一直使用<strong>大驼峰式</strong>(CamelCase)</li>
<li>常量名称:PHP 常量的名称必须全部使用<strong>大写</strong>字母</li>
<li>方法名称:PHP 方法的名称必须一直使用<strong>小驼峰式</strong>(camelCase)</li>
</ul>
<h3 id="psr-2严格的代码风格">PSR-2:严格的代码风格</h3>
<ul>
<li>贯彻 PSR-1</li>
<li>缩进:使用四个空格缩进。</li>
<li>文件和代码行:使用 UNIX 换行符(LF),文末<strong>留一个空行</strong>,<strong>不使用</strong> PHP 关闭标签 <code>?></code>。每行代码<strong>不超过</strong> 80 个字符,<strong>至少不能超过</strong> 120 个字符。每行末尾<strong>不能有空格</strong>。</li>
<li>关键字:使用<strong>小写字母</strong>。</li>
<li>命名空间:命名空间声明语句和 <code>use</code> 声明语句后<strong>留一个空行</strong>。</li>
<li>类:类定义体的起始括号在类名之后<strong>新起一行写</strong>。扩展类或实现接口的 <code>extends</code> 和 <code>implements</code> 关键字必须和类名<strong>写在同一行</strong>。</li>
<li>方法:方法定义体的起始括号要在方法名之后<strong>新起一行写</strong>。方法定义体的结束括号要在方法定义体之后新起一行写。起始圆括号之后<strong>没有空格</strong>,结束圆括号之前<strong>没有空格</strong>。方法的参数后面有<strong>一个逗号和空格</strong>。</li>
<li>可见性:类中的每个属性和方法都要声明可见性。<code>abstract</code> 或 <code>final</code> 限定符放在可见性关键字<strong>之前</strong>,<code>static</code> 限定符放在可见性关键字<strong>之后</strong>。</li>
<li>控制结构:所有控制结构关键字(<code>if</code>、<code>elseif</code>、<code>else</code>、<code>switch</code>、<code>case</code>、<code>while</code>、<code>do while</code>、<code>for</code>、<code>foreach</code>、<code>try</code>、<code>catch</code>)后面都要有<strong>一个空格</strong>。控制结构关键字后面的起始圆括号后面<strong>没有空格</strong>,结束圆括号之前<strong>没有空格</strong>,起始括号和控制结构关键字<strong>写在同一行</strong>,结束括号<strong>单独写在一行</strong>。</li>
</ul>
<h3 id="psr-3日志记录器接口">PSR-3:日志记录器接口</h3>
<ul>
<li>PSR-3 是一个接口,规定 PHP 日志记录器组件可以实现的方法。</li>
<li>PSR-3 要求日志记录器必须实现 9 个方法:</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o"><?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Psr\Log</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
</span></span></span><span class="line"><span class="cl"><span class="sd"> * for the full interface specification.
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">interface</span> <span class="nx">LoggerInterface</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">emergency</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">alert</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">critical</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">error</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">warning</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">notice</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">info</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">debug</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="k">public</span> <span class="k">function</span> <span class="nf">log</span><span class="p">(</span><span class="nv">$level</span><span class="p">,</span> <span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>推荐使用符合 PSR-3 规范的日志记录器 <a href="https://packagist.org/packages/monolog/monolog">monolog/monolog</a></li>
</ul>
<h3 id="psr-4自动加载器">PSR-4:自动加载器</h3>
<ul>
<li>PSR-4 是一个标准的自动加载器策略,规定运行时按需査找 PHP 类、接口或性状,并将其载入 PHP 解释器。</li>
<li>自动加载器的引入解决了使用 <code>require()</code> 函数和 <code>include()</code> 函数手动引入文件的繁琐。</li>
<li>PSR-4 推荐规范不要求改变代码的实现方式,只建议如何使用文件系统目录结构和 PHP 命名空间组织代码。</li>
<li>PSR-4 自动加载器策略依赖 PHP 命名空间和文件系统目录结构査找并加载 PHP 类、接口和性状。</li>
<li>PSR-4 会把命名空间的前缀和文件系统中的目录对应起来。命名空间的前缀可以是顶层命名空间,也可以是顶层命名空间加上任意一个子命名空间。</li>
<li>推荐使用依赖管理器 <a href="https://getcomposer.org/">Composer</a> 来自动生成符合 PSR-4 规范的自动加载器。</li>
</ul>
<h2 id="组件">组件</h2>
<ul>
<li>PHP 组件是一系列相关的类、接口和性状,用于解决某个具体问题。组件中的类、接口和性状通常放在同一个命名空间中。</li>
<li>好的 PHP 组件具有以下特征:
<ul>
<li>作用单一:专注于解决一个问题,而且使用简单的接口封装功能。</li>
<li>小型:只包含解决某个问题所需的最少代码。</li>
<li>合作:PHP 组件之间能良好合作。把代码放在自己的命名空间中,防止与其他组件有名称冲突。</li>
<li>测试良好:组件本身会提供测试,而且有充足的测试覆盖度。</li>
<li>文档完善:有个 README 文件,说明组件的作用,如何安装,以及如何使用。抑或有网站介绍详细信息。</li>
</ul>
</li>
<li>如果是能通过一些 PHP 组件准确解决问题的小型项目,那就使用组件。如果是有多个团队成员开发的大型项目,而且能从框架提供的约定、准则和结构中受益,那就使用框架。</li>
<li>查找组件目录:<a href="https://packagist.org/">Packagist</a></li>
<li>安装组件的工具:<a href="https://getcomposer.org/">Composer</a></li>
<li>自动加载是指在不使用 <code>require()</code>、<code>require_once()</code>、<code>include()</code> 或 <code>include_once()</code> 函数的情况下按需自动加载 PHP 类。</li>
<li>在较旧的 PHP 版本中可以使用 <code>autoload()</code> 函数自己编写自动加载器;实例化尚未加载的类时,PHP 解释器会自动调用这个函数。后来,PHP 在 SPL 库中引入了更灵活的 <code>sql_autoload_register()</code> 函数。如何自动加载 PHP 类完全由开发者决定。依赖管理器 Composer 为项目中的所有 PHP 组件自动生成符合 PSR 标准的自动加载器。Composers 有效抽象了依赖管理和自动加载。</li>
<li>Composer 和 Packagisti 都使用 <code>vendor/package</code> 这种命名约定,避免不同厂商的 PHP 组件有名称冲突。</li>
<li>PHP 组件版本号(如,1.13.2)语义:
<ol>
<li>第一个数字是主版本号,用于破坏了向后兼容性的版本更新。</li>
<li>第二个数字是次版本号,用于没破坏向后兼容性的小幅功能更新。</li>
<li>第三个数字是修订版本号,用于对向后兼容的缺陷的修正。</li>
</ol>
</li>
<li><code>composer install</code> 命令不会安装比 <code>composer.lock</code> 文件中列出的版本号新的版本。</li>
<li><code>composer update</code> 命令会把组件更新到最新稳定版,还会更新 <code>composer.lock</code> 文件,写入 PHP 组件的新版本号。</li>
<li>Composer 创建的自动加载器就是 <code>vendor/autoload.php</code> 文件。Composer 下载各个 PHP 组件时会检査每个组件的 <code>composer.json</code> 文件,确定如何加载该组件。</li>
<li>Composer 仓库的凭据 <code>auth.php</code> 文件放在和 <code>composer.json</code> 文件同级目录,且不应加入版本控制:</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"http-basic"</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"example.org"</span> <span class="o">:</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"username"</span><span class="o">:</span> <span class="s2">"your-name"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"password"</span><span class="o">:</span> <span class="s2">"your-password"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>composer.json</code> 文件结构:</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"name"</span><span class="o">:</span> <span class="s2">"组件名称"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"description"</span><span class="o">:</span> <span class="s2">"描述"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"keywords"</span><span class="o">:</span> <span class="p">[</span><span class="nx">关键词</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"homepage"</span><span class="o">:</span> <span class="s2">"组件主页"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"license"</span><span class="o">:</span> <span class="s2">"软件许可协议"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"authors"</span><span class="o">:</span> <span class="p">[</span><span class="nx">作者信息</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"support"</span><span class="o">:</span> <span class="p">{</span><span class="nx">获取技术支持的方式</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"require"</span><span class="o">:</span> <span class="p">{</span><span class="nx">依赖的组件</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"require-dev"</span><span class="o">:</span> <span class="p">{</span><span class="nx">开发该组件时依赖的组件</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"suggest"</span><span class="o">:</span> <span class="p">{</span><span class="nx">建议安装的组件</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"autoload"</span><span class="o">:</span> <span class="p">{</span><span class="nx">自动加载方式</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>Packagist 从组件的 <code>composer.json</code> 文件中读取了组件的名称、描述、关键字依赖和建议。还会发现显示了仓库的分支和标签。同时 Packagist 会把仓库的标签和语言版本号对应起来。</li>
</ul>
<h2 id="良好实践">良好实践</h2>
<h3 id="过滤验证和转义">过滤、验证和转义</h3>
<ul>
<li>不要相信任何来自不受自己直接控制的数据源中的数据。</li>
<li>过滤输入:转义或删除不安全的字符。在数据到达应用的存储层之前,一定要过滤输入数据。建议不使用正则表达式函数过滤 HTML,正则表达式很复杂,可能导致 HTML 无效,且出错的几率高。</li>
<li>验证数据:确认输入的数据符合预期,在应用的存储层保存符合特定格式的正确数据。避免数据库出现潜在的错误。</li>
<li>转义输出:避免渲染恶意代码,还能防止应用的用户无意中执行恶意代码。</li>
</ul>
<h3 id="密码">密码</h3>
<ul>
<li>绝对不能知道用户的密码</li>
<li>绝对不要约束用户的密码</li>
<li>绝对不能通过电子邮件发送用户的密码</li>
<li>使用 <code>bcrypt</code> 计算用户密码的哈希值。<code>bcrypt</code> 算法会自动加盐,防止潜在的彩虹表攻击。<code>bcrypt</code> 算法永不过时,如果计算机的运算速度变快了,我们只需提高工作因子的值。<code>bcrypt</code> 算法得到了同行的大量审查,目前暂无漏洞。</li>
<li>加密和哈希不是一回事。加密是双向算法,加密的数据以后可以解密。而哈希是单向算法,哈希后的数据不能再还原成原始值,而且相同的数据得到的哈希值始终相同。</li>
</ul>
<h3 id="日期时间和时区">日期、时间和时区</h3>
<ul>
<li>推荐使用 <a href="https://github.com/briannesbitt/Carbon"><code>nesbit/carbon</code></a> 组件处理日期和时间值的有用方法。</li>
</ul>
<h3 id="数据库">数据库</h3>
<ul>
<li>PDO 扩展:PDO(PHP Data Objects,PHP 数据对象)是一系列 PHP 类,抽象了不同数据库的具体实现,只通过一个用户界面就能与多种不同的 SQL 数据库通信。不管使用哪种数据库系统,使用一个接口就能编写和执行数据库査询</li>
<li>使用 PDO 时,建议编写符合 <code>ANSI/ISO</code> 标准的 SQL 语句,这样如果更换数据库系统 SQL 语句不会失效。</li>
<li>数据库凭据应保存在一个位于文档根目录之外的配置文件中,然后在需要使用凭据的 PHP 文件中导入。另外,凭据也不能纳入版本控制,避免因仓库公开而泄漏凭据。</li>
<li><strong>事务</strong>:指把一系列数据库语句当成单个逻辑单元(具有原子性)执行。事务中的一系列 SQL 査询要么都成功执行,要么根本不执行。</li>
<li>事务的一个副作用一一提升性能——事务把多个査询排成队列,一次全部执行。</li>
<li>PHP 中处理字符串的函数默认假设所有字符串都只使用 8 位字符,如果使用这些 PHP 原生的字符串函数处理包含多字节字符的 Unicode 字符串,可能会出错。为避免处理多字节字符串时出错,可以安装 <a href="http://php.net/manual/book.mbstring.php"><code>mbstring</code> 扩展</a>。该扩展提供了能替代大多数 PHP 原生的且能处理多字节字符串的函数。</li>
<li>PHP 编码配置(<code>pip.ini</code>):<code>default charset = "utf-8"</code></li>
</ul>
<h3 id="错误和异常">错误和异常</h3>
<ul>
<li>错误会导致程序脚本停止执行,有些错误无法恢复,其他错误可使用全局错误处理程序处理。</li>
<li>预测測、捕获并处理异常是我们自己的责任。未捕获的异常会导致 PHP 应用终止运行,显示致命错误信息。而更糟的是,可能会暴露敏感的调试详细信息,让应用的用户看到。因此,一定要使用 <code>try/catch</code> 块捕获异常,然后使用优雅的方式处理。</li>
<li>捕获某种异常时只会运行其中一个 catch 块。如果 PHP 没找到适用的 catch 块,异常会向上冒泡,直到 PHP 脚本由于致命错误而终止运行。</li>
<li>PHP 异常可以在 PHP 应用的任何层级抛出和捕获。</li>
<li>PHP 异常和错误设置原则:
<ul>
<li>一定要让 PHP 报告错误。</li>
<li>在开发环境中要显示错误。</li>
<li>在生产环境中不能显示错误。</li>
<li>在开发环境和生产环境中都要记录错误。</li>
</ul>
</li>
<li>推荐配置:</li>
</ul>
<pre tabindex="0"><code>; 开发环境
; 显示错误
display_startup_errors = On
display_errors = On
; 报告所有错误
error_reporting = -1
; 记录错误
log_errors = On
;生产环境
; 不显示错误
display_startup_errors = Off
display_errors = Off
; 除了注意事项之外,报告所有其他错误
error_reporting = E_ALL & ~E_NOTICE
; 记录错误
log_errors = On
</code></pre><ul>
<li>推荐使用 <a href="https://github.com/filp/whoops"><code>Whoops</code></a> 组件在开发环境中处理 PHP 错误和异常。</li>
<li>推荐使用 <a href="https://github.com/Seldaek/monolog"><code>Monolog</code></a> 组件在生产环境中记录 PHP 错误和异常。</li>
</ul>
<h2 id="主机">主机</h2>
<ul>
<li>存储 PHP 应用的四种方式:
<ul>
<li>共享服务器(Shared hosting)</li>
<li>虚拟私有服务器(VPS)</li>
<li>专用服务器</li>
<li>平台即服务(PasS)</li>
</ul>
</li>
<li>共享主机账户会与很多其他顾客的账户在同一个物理设备中。PHP 应用能使用多少设备在内存取决于这台设备中有多少账户。共享主机适合少预算,或简单需求。</li>
<li>虚拟私有服务器(VPS)提供了足够的系统资源,需要我们根据 PHP 应用的需求,自己动手配置和保护操作系统。</li>
<li>PasS 只需账号登陆,使用提供商的控制面板,单击按钮即可完成操作。有些 PasS 提供商会提供命令行工具或 Http Api,让我们部署和管理存储的 PHP 应用。适合小型 PHP 应用省心省事。</li>
</ul>
<h2 id="配置">配置</h2>
<h3 id="php-fpm">PHP-FPM</h3>
<ul>
<li>PHP-FPM 全局配置 <code>php-fpm.conf</code></li>
</ul>
<pre tabindex="0"><code>emergency_restart_threshold = 10
//在指定的一段时间内,如果失效的 PHP-FPM 子进程数超过这个值,PHP-FPM 主进程就优雅重启。
emergency_restart_interval = 1m
//设定 emergency_restart_threshold 设置采用的时间跨度。
</code></pre><ul>
<li>PHP-FPM 进程池配置 <code>fpm/pool.d/*.conf</code> 或 <code>php-fpm.d/*.conf</code></li>
</ul>
<pre tabindex="0"><code>user = deploy
//运行 PHP 应用的非根用户的用户名
group = deploy
//运行 PHP 应用的非根用户所属的用户组名
listen = 127.0.0.1:9000
//PHP-FPM 进程池监听的 IP 地址和端口号
listen.allowed_clients = 127.0.0.1
//可以向该 PHP-FPM 进程池发送请求的 IP 地址(一个或多个)。
pm.max_children = 51
//设定任何时间点 PHP-FPM 进程池中最多能有多少个进程。可以设置的值设为总内存 / 每个进程使用的内存大小
pm.start_servers = 3
//PHP-FPM 启动时 PHP-FPM 进程池中立即可用的进程数。建议设为 2 或 3。
pm.min_spare_servers = 2
//PHP 应用空闲时 PHP-FPM 进程池中可以存在的进程数量最小值。一般与 pm.start_servers 设置值一样
pm.max spare servers = 4
//PHP 应用空闲时 PHP-FPM 进程池中可以存在的进程数量最大值。一般比 pm.start_servers 设置的值大一点
pm.max requests = 1000
//回收进程之前,PHP-FPM 进程池中各个进程最多能处理的 HTP 请求数量。
slowlog = /path/to/slowlog log
//设置慢日志(处理时间超过 n 秒的 HTTP 请求信息)的绝对路径。注意 PHP-FPM 进程池所属的用户和用户组必须有这个文件的写权限。
request_slowlog_timeout = 5s
//慢日志记录的 HTTP 请求的时间下限,超过此值即记录慢日志
</code></pre><h3 id="nginx">Nginx</h3>
<pre tabindex="0"><code>server {
# Nginx 监听端口
listen 80;
# 虚拟主机的域名
server_name example.com;
# HTTP 请求 URI 没指定文件时访问的默认文件
index index.php;
# Nginx 接受 HTTP 请求主体长度的最大值
client_max_body_size 50M;
# 错误日志文件路径
error_log /home/deploy/apps/logs/example.error.log;
# 访问日志文件路径
access_log /home/deploy/apps/logs/example_access.log;
# 文档根目录路径
root /home/deploy/apps/example.com/current/public;
location / {
tryz_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
}
}
</code></pre><ul>
<li>指定匹配指定 URL 模式的 HTTP 请求。location / {} 块使用 try_files 指令依次进行如下操作:
<ol>
<li>査找匹配所请求 URI 的文件</li>
<li>查找匹配所请求 URI 的目录</li>
<li>把 HTTP 请求的 URI 重写为 /index.php,把査询字符附加到 URI 的末尾。</li>
</ol>
</li>
<li>重写的 URL 和所有以 .php 结尾的 URI 都由 location ~ .php {} 块管理,上例中该块规定把 HTTP 请求转发给 PHP-FPM 进程池处理。</li>
</ul>
<h2 id="优化">优化</h2>
<ul>
<li><code>php.ini</code> 配置中,建议修改 <code>upload_max_filesize = 10MB</code> 设置允许上传文件的大小</li>
<li><code>php.ini</code> 配置中,建议修改 <code>max_execution_time = 5</code> 设置单个 PHP 进程在终止之前最长可以运行多少时间。</li>
<li>应该在较少的块中发送更多的数据,而不是在较多的块中发送较少的数据,这样能减少 HTTP 请求总数。为此需要在 <code>php.ini</code> 配置中启用 PHP 输出缓存功能:</li>
</ul>
<pre tabindex="0"><code>output_buffering = 4096 // 输出缓存区大小
implicit_flush = false
</code></pre><h2 id="部署">部署</h2>
<p>使用 <a href="https://github.com/capistrano/capistrano">Capistrano</a> 来进行项目部署,可以方便地进行迭代和回滚操作。Capistrano 会在远程服务器中保存之前部署的应用,而且每次部署的版本放在各自的目录中。Capistrano 会维护五个或更多之前部署的应用,以防需要回滚到早前版本。Capistrano 还会创建一个 <code>current/</code> 目录,通过符号链接指向当前部署的应用所在的目录。具体步骤如下:</p>
<ol>
<li>在本地安装 ruby 和 gem</li>
<li>在本地安装 Capistrano:<code>$ gem install capistrano</code></li>
<li>在项目根目录进行初始化:<code>$ cap install</code>,产生的初始化文件结构如下:</li>
</ol>
<pre tabindex="0"><code>├── Capfile //配置文件
├── config //分环境配置文件
│ ├── deploy //环境配置目录
│ │ ├── production.rb //生产环境设置
│ │ └── staging.rb //过渡环境设置
│ └── deploy.rb //所有环境的通用设置
└── lib
└── capistrano
└── tasks
</code></pre><ol start="4">
<li>在远程服务器安装 Git:<code>$ yum install git</code></li>
<li>部署时在本地执行部署命令:<code>$ cap production deploy</code></li>
<li>回滚时在本地执行部署命令:<code>$ cap production deploy:rollback</code></li>
</ol>
<h2 id="测试">测试</h2>
<p>不同的测试方式之间不是互斥:</p>
<ul>
<li>单元测试:单独证实应用中的各个类、方法和函数能正常运行。PHP 通常使用 PHPUnit 单元测试框架进行单元测试。<a href="https://phpunit.de/">PHPUnit</a> 遵守 xUnit 测试架构。</li>
<li>测试驱动开发(Test-Driven Development, TDD):在编写应用代码之前先写测试。故意让测试失败以描述应用应该具有怎样的表现。开发好应用的功能后,最终测试会成功通过。</li>
<li>行为驱动开发(Behavior-Driven Development, BDD):编写故事,描述应用的表现。按导向不同氛围两类,二者一般可以共存互补,使项目获得更全面的测试。
<ul>
<li>SpecBDD 是一种单元测试,使用人类能读懂的流畅语言描述应用的实现方式。例如,可能会把某个 PHPUnit 测试命名为 <code>testrendertemplate()</code>,把等价的 SpecBDD 测试命名为 <code>itrendersthetemplate()</code>,和 Xunit 工具相比更易于阅读和理解。通常使用的 SpecBDD 测试工具是 <a href="http://www.phpspec.net/">PHPSPEC</a></li>
<li>StoryBDD 也使用人类能读懂的故事,不过 StoryBDD 关注更多的是整体行为,而不是低层实现。StoryBDD 测试关注项目整体的运行结果,而 SpecBDD 测试关注开发过程中的每个细节,如类、方法的正确性。通常使用的 StoryBDD 测试工具是 [Behat](<a href="http://behat.org/">http://behat.org/</a>)</li>
</ul>
</li>
</ul>
<h2 id="分析">分析</h2>
<ul>
<li>开发环境使用 <a href="http://xdebiug.org">XDebug</a>:使用时会消耗大量系统资源,借助 <a href="http://kcachegrind.sourceforge.net/">KCacheGrind</a> 和 <a href="https://sourceforge.net/projects/wincachegrind/">WinCacheGrind</a> 查看分析报告。</li>
<li>生产环境使用 <a href="http://xhprof.io">XHProf</a>:使用时会消耗的系统资源少,借助 XHGUI 查看分析报告。</li>
</ul>
<h2 id="hhvm-和-hack">HHVM 和 Hack</h2>
<ul>
<li>
<p>PHP 是传统意义上的解释型语言,而不是编译型语言。因此,在命令行或 Web 服务器调用解释器解释 PHP 代码之前,PHP 代码就是 PHP 代码。PHP 解释器会解释 PHP 脚本,把代码转换成一系列 <a href="http://php.net/manual/internals2.opcodes.php">Zend 操作码</a>(机器码指令),再把这些操作码交给 Zend Engine 执行。但解释型语言执行的速度比編译型语言慢很多,因为每次执行解释型语言编写的代码时都要将其转换成机器码,消耗额外的系统资源。</p>
</li>
<li>
<p>2010 年 Facebook 开发一个 HPHPc 的编译器,把 PHP 代码编译为 C++ 代码,再把 C++ 代码编译成可执行文件。但 HPHPc 对性能的提升已经到顶。于是 Facebook 开发了下一代 HPHPc,即 HHVM。HHVM 先把 PHP 代码转换成一种字节码中间格式,而且会缓存转换得到的字节码,然后使用 JIT 编译器转换并优化缓存的字节码,将其变成 x86_64 机器码。之后 HPHPc 被废弃。</p>
</li>
<li>
<p><a href="http://hacklang.org">Hack</a> 是一门服务器端语言,类似 PHP,且可以和 PHP 无缝集成。Hack 的开发者其实把 Hack 当做 PHP 的一种方言。从 PHP 转到 Hack 只需将 PHP 标签 <code><?php</code> 改为 <code><?hh</code> 即可。</p>
</li>
<li>
<p>Hack 既支持静态类型,也支持动态类型,且基本上能向后兼容普通的 PHP,所以其支持所有 PHP 动态类型特性。HHVM 读取 Hack 代码后会优化和缓存中间字节码,只在需要时才把 Hack 文件转换成 x86_64 机器码。Hack 充分利用了两种类型系统的特性,我们通过 Hack 的类型检査程序得到了静态类型的准确性和安全性,又通过 HVM 的 JIT 编译器得到了动态类型的灵活性和快速迭代。</p>
</li>
<li>
<p>Hack 自带一个单独的类型检査服务器,这个服务器在后台运行,会实时对代码做类型检査。</p>
</li>
<li>
<p>Hack 代码有三种編写模式:</p>
<ul>
<li>严格模式:<code><?hh // strict</code> 要求所有变量、函数、方法等代码都有合适的类型注解。且代码中不能有 Hack 之外的代码。</li>
<li>局部模式:<code><?hh // partial</code> 允许在 Hack 代码中使用还没转换成 Hack 的 PHP 代码。不要求注解函数或方法的所有参数,如果只注解部分参数,Hack 的类型检査程序也不会报错。</li>
<li>声明模式:<code><?php // decl</code> 允许严格模式的 Hack 代码调用未指定类型的代码。</li>
</ul>
</li>
<li>
<p>Hack 提供了 PHP 没有的新数据结构和接口数据结构:</p>
<ul>
<li><a href="https://docs.hhvm.com/hack/built-in-types/arrays">集合</a>(矢量,映射, 集和值对。)</li>
<li><a href="https://docs.hhvm.com/hack/generics/introduction">泛型</a></li>
<li><a href="https://docs.hhvm.com/hack/built-in-types/enumerated-types">枚举</a></li>
<li><a href="https://docs.hhvm.com/hack/built-in-types/shapes">形状</a></li>
<li><a href="https://docs.hhvm.com/hack/built-in-types/tuples">元组</a></li>
</ul>
</li>
</ul>
《精通正则表达式》学习笔记(六)
https://acuario.xyz/posts/mastering-regex-summary-6/
2023-09-27T18:25:39+00:00
2019-08-17T23:00:53+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="php-的正则流派">PHP 的正则流派</h2>
<ul>
<li>PHP 的三种正则引擎是 <code>preg</code>、<code>ereg</code> 和 <code>mb_ereg</code>。</li>
<li>在默认情况下,preg 套件的正则表达式是以字节为单位的,所以「<code>\C</code>」默认等价于「<code>(?d:.)</code>」,由 <code>s</code> 修饰的点号。不过,如果使用了修饰符 <code>u</code>,则 preg 套件就会以 UTF-8 字母为单位,也就是说,一个字符可能由 6 个字节组成。即使这样,「<code>\C</code>」仍然匹配单个字节。</li>
<li>「<code>\z</code>」和「<code>\Z</code>」都能够匹配字符串的末尾,而「<code>\Z</code>」同样能够匹配最后的换行符。</li>
<li>「<code>$</code>」的意义取决于模式修饰符 <code>m</code> 和 <code>D</code>:如果没有设定任何修饰符,「<code>$</code>」等价于「<code>\Z</code>」(在字符串结尾的换行符,或者是字符串结尾);如果使用了 <code>m</code>,则它能够匹配内嵌的换行符,如果使用了模式修饰符 <code>D</code>,它能够匹配「<code>\z</code>」(只有在字符串的结尾)。如果同时设置了 <code>m</code> 和 <code>D</code>,则忽略 <code>D</code>。</li>
<li>PHP 正则引擎的处理方式完全是<strong>程序式</strong>的。</li>
</ul>……
<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="php-的正则流派">PHP 的正则流派</h2>
<ul>
<li>PHP 的三种正则引擎是 <code>preg</code>、<code>ereg</code> 和 <code>mb_ereg</code>。</li>
<li>在默认情况下,preg 套件的正则表达式是以字节为单位的,所以「<code>\C</code>」默认等价于「<code>(?d:.)</code>」,由 <code>s</code> 修饰的点号。不过,如果使用了修饰符 <code>u</code>,则 preg 套件就会以 UTF-8 字母为单位,也就是说,一个字符可能由 6 个字节组成。即使这样,「<code>\C</code>」仍然匹配单个字节。</li>
<li>「<code>\z</code>」和「<code>\Z</code>」都能够匹配字符串的末尾,而「<code>\Z</code>」同样能够匹配最后的换行符。</li>
<li>「<code>$</code>」的意义取决于模式修饰符 <code>m</code> 和 <code>D</code>:如果没有设定任何修饰符,「<code>$</code>」等价于「<code>\Z</code>」(在字符串结尾的换行符,或者是字符串结尾);如果使用了 <code>m</code>,则它能够匹配内嵌的换行符,如果使用了模式修饰符 <code>D</code>,它能够匹配「<code>\z</code>」(只有在字符串的结尾)。如果同时设置了 <code>m</code> 和 <code>D</code>,则忽略 <code>D</code>。</li>
<li>PHP 正则引擎的处理方式完全是<strong>程序式</strong>的。</li>
</ul>
<h2 id="preg-函数接口">Preg 函数接口</h2>
<table>
<thead>
<tr>
<th>函数</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>preg_match</code></td>
<td>测试正则表达式能否在字待串中找到匹配,并提取数据</td>
</tr>
<tr>
<td><code>preg_match_all</code></td>
<td>从字苻串中提取数据</td>
</tr>
<tr>
<td><code>preg_replace</code></td>
<td>在字待串的副本中替换匹配的文本</td>
</tr>
<tr>
<td><code>preg_replace_callback</code></td>
<td>对字特事中的每处匹配文本调用处理函数</td>
</tr>
<tr>
<td><code>preg_split</code></td>
<td>将字苻串切分为子串数组</td>
</tr>
<tr>
<td><code>preg_grep</code></td>
<td>选出数组中能/不能由表达式匹配的元素</td>
</tr>
<tr>
<td><code>preg_quote</code></td>
<td>转义字符串中的正则表达式元字符</td>
</tr>
</tbody>
</table>
<h3 id="pattern-参数">pattern 参数</h3>
<ul>
<li><code>patten</code> 参数是包含在一对斜线(分隔符)里头的参数。分隔符后面是模式修饰符。其参数的组成:
<ol>
<li>分隔符</li>
<li>正则表达式</li>
<li>模式修饰符</li>
</ol>
</li>
</ul>
<h4 id="分隔符">分隔符</h4>
<ul>
<li>preg 引擎要求正则表达式两端必须有分隔符,因为设计者希望它看起来更像 Perl,尤其在模式修饰符的使用方法上更是如此。</li>
<li>可以使用除了字母、数字、反斜线和空白字符之外的任何 ASCI 字符做分隔符。最常见的是一对斜线,或者两个 <code>!</code>、<code>#</code>。</li>
<li>分隔符的选取应该考虑实际情况,避免产生嵌套。如正则表达式内如果存在括号 <code>()</code>,则应该避免使用 <code>()</code> 作为分隔符。</li>
</ul>
<h4 id="正则表达式">正则表达式</h4>
<ul>
<li>因为正则表达式很有可能包含反斜线,所以在以字符串文字方式提供 pattern 参数时,最好使用 PHP 的单引号字符串,这样可以省略许多额外的转义。</li>
</ul>
<h4 id="模式修饰符">模式修饰符</h4>
<ul>
<li>表达式内部的模式修饰符:在正则表达式内部,模式修饰符可以单独出现,来启用或停用某些特性,其作用范围持续到对应的结束括号。</li>
</ul>
<table>
<thead>
<tr>
<th>标准修饰符</th>
<th>用途</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>i</code></td>
<td>「<code>(?!)</code>」</td>
<td>忽略大小写</td>
</tr>
<tr>
<td><code>m</code></td>
<td>「<code>(?m)</code>」</td>
<td>增强的行铺点模式</td>
</tr>
<tr>
<td><code>s</code></td>
<td>「<code>(?s)</code>」</td>
<td>点号通配模式</td>
</tr>
<tr>
<td><code>x</code></td>
<td>「<code>(?x)</code>」</td>
<td>宽松排列和注释模式</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>PHP 特有修饰符</th>
<th>用途</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>u</code></td>
<td></td>
<td>在 UTF-8 编码中,非 ASCI 字符以多个字节来存储,使用 <code>u</code> 修饰符能够以 UTF-8 编码处理正则表达式和目标字符串,确保多个字节会被作为单个字符来处理。处理时也不会修改数据,只是更改正则引擎处理数据的方式</td>
</tr>
<tr>
<td><code>S</code></td>
<td></td>
<td>启用 PCRE 的 “study” 优化特性,预先分析正则表达式,在某些顺利的情况下,在尝试匹配时速度会大大提升</td>
</tr>
<tr>
<td><code>D</code></td>
<td></td>
<td>把每个「<code>$</code>」替换为「<code>\z</code>」,即「<code>$</code>」匹配字符串的末尾,而不是字符串之内的换行符。</td>
</tr>
<tr>
<td><code>A</code></td>
<td></td>
<td>把匹配锚定在第一次尝试的位置</td>
</tr>
<tr>
<td><code>X</code></td>
<td>「<code>(?X)</code>」</td>
<td>启用 PCRE “额外功能(extra stuff)”,报告非无法识别的反斜线序列</td>
</tr>
<tr>
<td><code>e</code></td>
<td></td>
<td>将 replacement 作为 PHP 代吗(只用于 <code>preg_replace</code>)</td>
</tr>
<tr>
<td><code>U</code></td>
<td>「<code>(?U)</code>」</td>
<td>交换「<code>*</code>」和「<code>*?</code>」的匹配优先含义,<strong>建议不使用</strong></td>
</tr>
</tbody>
</table>
<h2 id="preg-函数罗列">Preg 函数罗列</h2>
<h3 id="preg_match"><code>preg_match</code></h3>
<pre tabindex="0"><code>int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
</code></pre><ul>
<li><code>$matches</code> 末尾的空字符串都会被忽略。</li>
<li>使用命名捕获会使代码更易读,但使用了命名捕获,按数字编号的捕获仍然会插人 <code>$matches</code>。所以不推荐同时使用命名和数字编号来访问 <code>$matches</code> 的元素。</li>
</ul>
<p><img src="https://i.loli.net/2019/08/06/2tTh3QbLRim67zO.png" alt="命名捕获"></p>
<ul>
<li>参数 flags 可使用参数值:<code>PREG_OFFSET_CAPTURE</code> 使第 1 个元素是匹配的文本,第 2 个元素是这段文本在目标字符串中的偏移值。其通常按照<strong>字节</strong>来计数。</li>
</ul>
<h3 id="preg_match_all"><code>preg_match_all</code></h3>
<pre tabindex="0"><code>int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )
</code></pre><ul>
<li>每个匹配都会创建一个包含匹配数据的数组,所以最后 matches 变量就是一个二维数组,其中的每个子数组对应一次匹配。</li>
<li>参数 flags 可使用参数值 <code>PREG_PATTERN_ORDER</code> 和 <code>PREG_SET_ORDER</code> 用于制定排列方式:</li>
</ul>
<table>
<thead>
<tr>
<th>类型</th>
<th>标志位</th>
<th>说明及示例</th>
</tr>
</thead>
<tbody>
<tr>
<td>按分组号</td>
<td><code>PREG_PATTERN_ORDER</code></td>
<td>将各次匹配中同样编号的分组编在一起</td>
</tr>
<tr>
<td>堆叠</td>
<td><code>PREG_SET_ORDER</code></td>
<td>将每次匹配的数据集中保存</td>
</tr>
</tbody>
</table>
<h3 id="preg_replace"><code>preg_replace</code></h3>
<pre tabindex="0"><code>mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
</code></pre><ul>
<li>对文本进行査找-替换的办法。</li>
<li><code>subject</code> 也可以是一个字符串数组,搜索和替换是对每个字符串依次进行的。</li>
<li><code>pattern</code> 和 <code>replacement</code> 参数也可以是字符申数组。</li>
<li>如果 <code>subject</code> 参数是数组,则依次处理数组中的每个元素,返回值也是字符串数组。</li>
<li><code>preg_replace</code> 的程序要使用 <code>each()</code> 来按照数组的内部顺序历整个数组,而不关心它们的 keys 如何。</li>
<li>如果 <code>pattern</code> 或 <code>replacement</code> 数组的内部顺序不同于你希望匹配的顺序,可以使用 <code>sort()</code> 函数来确保每个数组的实际顺序和外表顺序是相同的。</li>
</ul>
<h3 id="preg_replace_callback"><code>preg_replace_callback</code></h3>
<pre tabindex="0"><code>mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] )
</code></pre><ul>
<li><code>replacement</code> 参数变成了 PHP 回调函数,而不是字符串或是字符串数组。</li>
</ul>
<h3 id="preg_split"><code>preg_split</code></h3>
<pre tabindex="0"><code>array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )
</code></pre><ul>
<li><code>preg_split</code> 找出目标字符串中不能由正则表达式匹配的部分。返回目标字符串中正则表达式匹配的部分別去之后的部分。相当于 PHP 中内建的简单 <code>explode</code> 函数,不过使用的是正则表达式,而且功能更强大。</li>
<li><code>limit</code> 参数用来设定切分之后数组长度的上限。达到 <code>limit</code> 之后的文本内容会全部保存到最后的元素当中。</li>
<li>参数 flags 可使用参数值:
<ul>
<li><code>PREG_SPLIT_OFFSET_CAPTURE</code> 标志位会修改结果数组,把每个元素变为包含两个元素的数组(元素本身和它在字符串中的偏移值)。</li>
<li><code>PREG_SPLIT_NO_EMPTY</code> 标志位告诉 <code>preg_split</code> 忽略空字符串。</li>
<li><code>PREG_SPLIT_DELIM_CAPTURE </code> 标志位在结果中包含匹配的文本,以及捕获括号匹配的文本。</li>
</ul>
</li>
</ul>
<h3 id="preg_grep"><code>preg_grep</code></h3>
<pre tabindex="0"><code>preg_grep ( string $pattern , array $input [, int $flags = 0 ] ) : array
</code></pre><ul>
<li><code>preg_grep</code> 生成 <code>$input</code> 数组的副本,其中只保留了 <code>$value</code> 能够匹配 <code>$pattern</code> 的元素。</li>
</ul>
<h3 id="preg_quote"><code>preg_quote</code></h3>
<pre tabindex="0"><code>preg_quote ( string $str [, string $delimiter = NULL ] ) : string
</code></pre><ul>
<li>转义正则表达式字符,向其中每个正则表达式语法中的字符前增加一个反斜线。</li>
</ul>
<h2 id="效率">效率</h2>
<ol>
<li>回调函数通常要比模式修饰符 <code>e</code> 更快;</li>
<li>在太长的目标字符串中使用命名捕获必须进行更多的数据拷贝。</li>
<li>除非把同一个表达式应用到大规模的文本,或者大量小规模文本时,オ需要考虑模式修饰符 <code>S</code>。</li>
</ol>
《精通正则表达式》学习笔记(五)
https://acuario.xyz/posts/mastering-regex-summary-5/
2023-09-27T18:25:39+00:00
2019-08-08T00:17:53+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<ul>
<li>因为 NFA 引擎容许用户进行精确控制,所以我们可以用心打造正则表达式。</li>
<li>调校表达式时需要考虑的两个因素是<strong>准确性</strong>和<strong>效率</strong>:精确匹配文本而不包含多余的内容,且速度要快。</li>
<li>优化表达式的关键在于彻底理解回溯背后的过程,学习些技巧来避免可能的回溯。</li>
<li>不同工具可能使用不同的优化措施。如果能够预先判断目标字符串基本无法匹配(例如目标宇符串缺少一个引擎能够预知的,匹配成功必须的字符),足够聪明的实现方式可以完全不应用正则表达式。</li>
<li>在分析效率时,不要忘了不同正则引擎的差异。</li>
</ul>……
<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<ul>
<li>因为 NFA 引擎容许用户进行精确控制,所以我们可以用心打造正则表达式。</li>
<li>调校表达式时需要考虑的两个因素是<strong>准确性</strong>和<strong>效率</strong>:精确匹配文本而不包含多余的内容,且速度要快。</li>
<li>优化表达式的关键在于彻底理解回溯背后的过程,学习些技巧来避免可能的回溯。</li>
<li>不同工具可能使用不同的优化措施。如果能够预先判断目标字符串基本无法匹配(例如目标宇符串缺少一个引擎能够预知的,匹配成功必须的字符),足够聪明的实现方式可以完全不应用正则表达式。</li>
<li>在分析效率时,不要忘了不同正则引擎的差异。</li>
</ul>
<h3 id="多选分支的顺序优化">多选分支的顺序优化</h3>
<p>期望:匹配引号字符串(允许转义双引号)<br>
RegEx:<code>"(\\.|[^\\"])*"</code></p>
<ul>
<li><strong>多选分支的顺序很重要,其会影响回溯的发生与否和发生回溯的先后顺序。</strong></li>
<li>调换「<code>\\.</code>」和「<code>[^\\"]</code>」的顺序,只有在遇到字符串中的转义字符时才会按照多选结构进行回溯,这样增加了第一个多选分支的成功匹配次数,有效减少回溯的次数。</li>
<li>为提高效率修改正则表达式时最需要考虑的问题是,改动是否会影响匹配的准确性。在关注效率的时候,万不可忘记准确性。<em>重新安排多选分支的顺序</em>这种操作,只有在排序与匹配成功无关时才不会影响准确性。</li>
<li>在任意正则表达式中,星号会对每个普通字符进行迭代(或者说“重复"),重复进入一退出多选结构(和括号)。星号量词作用于括号内的子表达式,每次迭代都需要进入然后再退出括号,因为引擎需要记录括号内的子表达式匹配的文本。为此必须进行处理。</li>
<li>优化表达式时,使一次迭代中读入尽可能多的字符,尽量减少发生回溯的次数,把星号迭代的次数减少到最小:</li>
</ul>
<p><img src="https://i.loli.net/2019/07/25/5d3925bdeb92a68557.jpg" alt=""></p>
<h3 id="指数级匹配超线性super-linear">指数级匹配(超线性,super-linear)</h3>
<ul>
<li>表达式「<code>"([^\\"]+|\\.)*"</code>」在 POSIX NFA 中匹配 <code>very ...... long</code> 时需要超过 3 亿亿亿次回溯。因为正则表达式中某个元素受加号限定的同时,还受括号外的星号限定,无法区分哪个量词控制哪个特殊的字符。</li>
<li>对正则表达式「<code>([^\\"]+)*</code>」来说,加号和星号二者分割(divvy up)字符串的可能性是成指数形式增长的。</li>
<li>对不同类型引擎指数级匹配的差异:
<ul>
<li>如果其中的某个表达式,即使不能匹配,也能很快给出结果,那可能就是 DFA。</li>
<li>如果只有在能够匹配时才很快出结果,那就是传统型 NFA。</li>
<li>如果总是很慢,那就是 POSIX NFA。</li>
</ul>
</li>
</ul>
<h3 id="回溯实例">回溯实例</h3>
<h4 id="匹配成功的回溯">匹配成功的回溯</h4>
<ul>
<li>从局部来看,回溯就是倒退至未尝试的分支。</li>
</ul>
<p><img src="https://i.loli.net/2019/07/26/5d3a6ab8dec8f93141.jpg" alt="图像 (9).jpg"></p>
<ul>
<li>表达式「<code>".*"</code>」在 <strong>NFA</strong> 引擎中的匹配过程如图所示:
<ol>
<li>多次匹配失败直到 A 处</li>
<li>从 <code>A-B</code> 处均匹配成功,并在每个位置(共计 46 处)撒下面包屑,记录保存状态</li>
<li>从 <code>B-C</code> 开始逐步回溯,直到 <code>C</code> 处匹配成功</li>
</ol>
</li>
<li>表达式「<code>".*"</code>」在 <strong>POSIX NFA</strong> 引擎中的匹配过程与 <strong>NFA</strong> 类似,但为了确认<em><strong>最长的匹配</strong></em>,还需进行一些确认操作:
<ol>
<li>多次匹配失败直到 <code>A</code> 处</li>
<li>从 <code>A-B</code> 处均匹配成功,并在每个位置(共计 46 处)撒下面包屑,记录保存状态</li>
<li>从 <code>B-C</code> 开始逐步回溯,知道 <code>C</code> 处匹配成功</li>
<li>尝试过程 <code>D-E-F</code> 和 <code>F-G-H</code> 类似 <code>B-C-D</code>,只是 <code>F</code> 和 <code>H</code> 会被抛弃,因为它们匹配的文本都比 <code>D</code> 更短</li>
<li><code>I</code> 位置完成当前匹配的所有回溯,重新启动驱动过程,进行下一轮匹配尝试。但由于已经有匹配成功的文本,所以直接返回匹配结果。</li>
</ol>
</li>
</ul>
<h4 id="无法匹配成功的回溯">无法匹配成功的回溯</h4>
<p>表达式「<code>".*"!</code>」无法匹配范例文本,在匹配过程中进行多轮匹配尝试,每次尝试都有回溯产生,其匹配过程如图所示:</p>
<p><img src="https://i.loli.net/2019/07/26/5d3a6ab8eee6752532.jpg" alt=""></p>
<h4 id="通过优化表达式来减少回溯">通过优化表达式来减少回溯</h4>
<p>表达式「<code>"[^"]*"!</code>」通过使用「<code>[^"]</code>」来替代「<code>.*</code>」,通过减少可能匹配的字符,从而大大降低了回溯产生的次数。减少的回溯就是有意的<strong>伴随效应(side effect)</strong></p>
<p><img src="https://i.loli.net/2019/07/26/5d3a6ab8c8c5e54462.jpg" alt=""></p>
<h4 id="多选结构的回溯">多选结构的回溯</h4>
<p>使用多选结构时,需要注意引起的回溯对性能的影响。</p>
<p>文本:<code>The name "McDonald's" is said "makudonarudo" in Japanese</code>.<br>
期望:<code>makudonarudo</code></p>
<p>{% raw %}</p>
<table>
<thead>
<tr>
<th>RegEx</th>
<th>回溯次数</th>
</tr>
</thead>
<tbody>
<tr>
<td>「<code>[uvwxyz]</code>」</td>
<td>34</td>
</tr>
<tr>
<td>「<code>u|v|w|x|y|z</code>」</td>
<td>204</td>
</tr>
</tbody>
</table>
{% endraw %}
<h3 id="常见优化原理">常见优化原理</h3>
<ul>
<li>提高匹配效率的优化原理主要有:
<ol>
<li><strong>加速某些操作</strong></li>
<li><strong>避免冗余操作</strong></li>
</ol>
</li>
<li>只有在检测优化措施是否可行所需的时间少于节省下来的匹配时间的情况下,优化才是有益的。</li>
<li>优化所需的时间、节省的时间、优化的可能性这三者间存在互相制约的关系。</li>
</ul>
<h4 id="应用前的优化">应用前的优化</h4>
<ul>
<li>编译缓存:
<ul>
<li>正则表达式使用之前先进行错误检查,之后编译为内部形式检查字符串。</li>
<li>为提高编译效率,首次编译之后的内部形式会被保存或缓存下来,在此后的循坏中复用。</li>
<li>集成式处理中的编译缓存:正则表达式可能每次循环都会变化,优化措施是检査插值后的结果(也就是正则表达式的具体值),只有当具体值发生变化时才重新编译。</li>
<li>集成式处理中的编译缓存:编译形式与表达式在程序中所处的具体位置相关,正则表达式变化时,先检査插值后的结果(即正则表达式的具体值),当具体值发生变化时才重新编译。</li>
<li>程序式处理中的编译缓存:
<ul>
<li>编译形式与表达式在程序中所处的具体位置无关,每次调用函数时,正则表达式必须重新编译。</li>
<li>将最近使用的正则表达式模式(regex pattern)缓存后关联到最终的编译形式。</li>
<li>调用“应用此表达式”函数之后,作为参数的正则表达式模式会与保存的正则表达式相比较,如果已存在于缓存中,就使用缓存的版本。如果没有,就直接编译这个正则表达式,将其存入缓存。无可用缓存时,丢弃一个最久未使用的编译形式。</li>
</ul>
</li>
<li>面向对象式处理中的编译缓存:正则表达式何时编译完全由程序决定。通过构造函数来进行编译。通过对象析构函数抛弃编译好的正则表达式。</li>
</ul>
</li>
<li>预查(子)字符串优化:在实际应用正则表达式之前,在目标字符串中快速扫描,检査所需的字符或者字符串一如果不存在,根本就不需要进行任何尝试。</li>
<li>长度判断优化:预先判断目标文本的长度是否满足正则表达式要求的最小长度,若不满足,则不进行任何尝试。</li>
</ul>
<h4 id="传动装置的优化">传动装置的优化</h4>
<p>{% raw %}</p>
<table>
<thead>
<tr>
<th>优化策略</th>
<th>释义</th>
<th>栗子</th>
</tr>
</thead>
<tbody>
<tr>
<td>字符串起始 / 行锚点</td>
<td>任何以「<code>^</code>」开头的正则表达式只能在「<code>^</code>」能够匹配的情况下才可能匹配。</td>
<td>「<code>^this|^that</code>」修改为「<code>^(this|that)</code>」或 「<code>^(?:this|that)</code>」</td>
</tr>
<tr>
<td>隐式锚点</td>
<td>如果正则表达式以「<code>.*</code>」或「<code>.+</code>」开头,且没有全局性多选结构(global alternation),则可以认为此正则表达式的开头有一个看不见的「<code>^</code>」。则使用上一节的“字符串起始 / 行锚点优化”,节省大量的时间。</td>
<td></td>
</tr>
<tr>
<td>字符串结束 / 行锚点</td>
<td>遇到末尾为「<code>$</code>」或其他结束锚点的正则表达式时,能够从字符申末尾倒数若干字符的位置开始尝试匹配。</td>
<td>「<code>regex(es)?$</code>」从倒数第 8 个字符开始匹配</td>
</tr>
<tr>
<td>开头字符 / 字符组 / 子串识别</td>
<td>容许传动装置预先检查字符串中的每个字符,只在可能匹配的位置进行应用,这样能节省大量的时间。避免从错误的位置开始执行匹配尝试。</td>
<td>「<code>this|that|other</code>」只能从「<code>[ot]</code>」位置开始匹配</td>
</tr>
<tr>
<td>内嵌文字字符串检查</td>
<td>类似初始字符串识别优化,使用高速的 Boyer-Moore 字符串检索算法寻找目标位置。</td>
<td></td>
</tr>
<tr>
<td>长度识别传动</td>
<td>当前位置距离字符申末尾的长度小于成功匹配所需最小长度,传动装置会停止匹配尝试。</td>
<td></td>
</tr>
</tbody>
</table>
{% endraw %}
<h4 id="正则表达式本身的优化">正则表达式本身的优化</h4>
<ul>
<li>文字字符串连接:把多个字符串当作整体而非分离的个体,例如将「<code>abc</code>」视为整体而非,「<code>a</code>」然后「<code>b</code>」然后「<code>c</code>」。</li>
<li>化简量词:约束普通元素的加号、星号之类的量词。避免普通 NFA 引擎的大部分逐步处理开销(step-by-step overhead)。例如「<code>.*</code>」和「<code>(?:.)*</code>」在逻辑上是相等的,但是在进行此优化的系统中,「<code>.*</code>」实际上更快。</li>
<li>消除无必要括号:使用无括号的等价的表达式进行替换。如使用「<code>.*</code>」替换「<code>(?:.)*</code>」。</li>
<li>消除不需要的字符组:将只包含单个字符的字符组在内部进行转换。如「<code>[.]</code>」转换为「<code>\.</code>」。</li>
<li>忽略优先量词之后的字符优化:忽略优先量词通常比匹配优先量词要慢。如果文字字符跟在忽略优先量词之后,只要引擎没有触及那个文字字符,忽略优先量词可以作为普通的匹配优先量词来处理,从而跳过常规的“忽略”状态。</li>
<li>“过度”回溯检测:限定回溯堆栈的大小,即限定回溯的次数,在“超限”时停止匹配。</li>
<li>避免指数级匹配:在匹配尝试进入超线性状态时进行检测,记录每个量词对应的子表达式尝试匹配的位置,绕过重复尝试。</li>
<li>使用占有优先量词削减状态:不保留“在此处不进行匹配”的状态,在量词全部尝试完成之后抛弃所有备用状态,每一轮迭代时抛弃上轮的备用状态。否则,如应用「<code>.*</code>」会在匹配每个字符时创造一个状态,如果字符串很长,会占用大量的内存。</li>
<li>量词等价转换:根据不同语言的正则表达式特性,对量词进行替换,如「<code>\d\d\d\d</code>」替换为「<code>\d{4}</code>」。</li>
<li>需求识别:预先取消它认为对匹配结果没有价值的工作。</li>
</ul>
<h3 id="常见优化方法">常见优化方法</h3>
<p>{% raw %}</p>
<table>
<thead>
<tr>
<th>优化方法</th>
<th>释义</th>
<th>栗子</th>
</tr>
</thead>
<tbody>
<tr>
<td>避免重新编译</td>
<td>编译和定义正则表达式的次数应该尽可能的少。在循环外创建正则表达式对象,在循环中重复使用。函数式处理要保证循环中使用的正则表达式的数目少于工具所能缓存的上限。集成式处理避免在循环内的正则表达式中使用变量插值。</td>
<td></td>
</tr>
<tr>
<td>使用非捕获型括号</td>
<td>不需要引用的文本,使用非捕获型括号「<code>(?:...)</code>」节省捕获时间,减少回溯使用的状态的数量。</td>
<td></td>
</tr>
<tr>
<td>不要滥用括号</td>
<td>使用括号会阻止某些优化措施。</td>
<td></td>
</tr>
<tr>
<td>不要滥用字符组</td>
<td>使用元字符来替代单个字符的字符组</td>
<td>使用「<code>\.</code>」来替代「<code>[.]</code>」</td>
</tr>
<tr>
<td>使用起始锚点</td>
<td>以「<code>.*</code>」开头的正则表达式都应该在最前面添加「<code>^</code>」或者「<code>\A</code>」。配合开头字符 / 字符串 / 字串识别优化,节省不必要的工作。</td>
<td></td>
</tr>
<tr>
<td>将文字文本独立出来</td>
<td>“提取”必要元素:暴露必须的匹配内容。</td>
<td>使用「<code>xx*</code>」替代「<code>x+</code>」暴露匹配 <code>x</code>,使用「<code>------{0,2}</code>」替代「<code>-{5,7}</code>」暴露匹配 <code>-</code>。</td>
</tr>
<tr>
<td>将文字文本独立出来</td>
<td>“提取”多选结构开头的必须元素</td>
<td>使用「<code>------{0,2}</code>」替代「<code>-{5,7}</code>」暴露匹配 <code>-</code>。</td>
</tr>
<tr>
<td>将锚点独立出来</td>
<td>在表达式前面独立出 <code>^</code> 和 <code>\G</code></td>
<td></td>
</tr>
<tr>
<td>将锚点独立出来</td>
<td>在表达式末尾独立出 <code>$</code></td>
<td></td>
</tr>
</tbody>
</table>
{% endraw %}
<ul>
<li>如果目标字符串很长:
<ul>
<li>分号接近字符串的开头,使用忽略优先量词。</li>
<li>分号接近宇符串末尾的位置,使用匹配优先量词。</li>
<li>若是随机数据,又不知道分号接近文首或文尾,则使用匹配优先的量词。</li>
</ul>
</li>
<li>如果目标字符串很短,使用何种优先量词无所谓。</li>
<li>多个小正则表达式的速度比一个大正则表达式要快得多。</li>
<li>在表达式的开头添加合适的环视结构,可以让表达式对文本进行“预査”,选择合适的开始位置。</li>
<li>固化分组和占有优先量词能够极大地提高匹配速度,而不会改变匹配结果。</li>
<li>主导引擎的匹配
<ul>
<li>将最可能匹配的多选分支放在前头:许多时候多选分支的摆放顺序比优化更重要,但如果顺序与匹配正确无关,就应该把最可能匹配的多选分支放在首位。这一点只对传统型 NFA 引擎且只有存在匹配的时候才适用。对 POSIX NFA 或不存在匹配时,所有的多选分支都必须检测,所以顺序是无关紧要的。</li>
<li>将结尾部分分散到多选结构内:把尾部通配表达式加到多选结构之内,匹配时不需要退出多选结构就能发现失败,则匹配失败的更快。</li>
</ul>
</li>
<li>各种优化都是平等的,在优化时请务必小心,不要因小失大。</li>
</ul>
SSH配置登陆密钥和别名
https://acuario.xyz/posts/configure-ssh-host-and-keychain/
2023-09-27T18:25:39+00:00
2019-07-30T00:30:07+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="前言">前言</h2>
<p>通常在 Shell 中使用 SSH 连接远程服务器时,我们需要输入完整的 SSH 命令,如:</p>
<pre tabindex="0"><code>$ ssh user@example.com #连接远端22端口并输入密码登陆
</code></pre><p>然后根据提示输入 <code>user</code> 用户的密码登陆主机。</p>
<p>有两个常用的参数:</p>
<ul>
<li><code>-p</code> 指定其他 SSH 端口,如 SSH 端口非 22 端口,可用此参数指定</li>
<li><code>-i</code> 指定私钥通过密钥登陆,可配置好密钥后对免密登陆</li>
</ul>
<pre tabindex="0"><code>## 连接远端1234端口
$ ssh user@example.com -p 1234
## 使用私钥id_rsa登陆
$ ssh user@example.com -i ~/.ssh/id_rsa
</code></pre><p>但是随着手头服务器配置的增加,而不同服务器 IP、端口、用户、使用的密钥均不同,每次繁琐地查询和输入这么多配置和参数实在是麻烦,何况我怎么记得住这么多 IP 地址啊!(主要还是因为懒</p>……
<h2 id="前言">前言</h2>
<p>通常在 Shell 中使用 SSH 连接远程服务器时,我们需要输入完整的 SSH 命令,如:</p>
<pre tabindex="0"><code>$ ssh user@example.com #连接远端22端口并输入密码登陆
</code></pre><p>然后根据提示输入 <code>user</code> 用户的密码登陆主机。</p>
<p>有两个常用的参数:</p>
<ul>
<li><code>-p</code> 指定其他 SSH 端口,如 SSH 端口非 22 端口,可用此参数指定</li>
<li><code>-i</code> 指定私钥通过密钥登陆,可配置好密钥后对免密登陆</li>
</ul>
<pre tabindex="0"><code>## 连接远端1234端口
$ ssh user@example.com -p 1234
## 使用私钥id_rsa登陆
$ ssh user@example.com -i ~/.ssh/id_rsa
</code></pre><p>但是随着手头服务器配置的增加,而不同服务器 IP、端口、用户、使用的密钥均不同,每次繁琐地查询和输入这么多配置和参数实在是麻烦,何况我怎么记得住这么多 IP 地址啊!(主要还是因为懒</p>
<h2 id="配置密钥登陆">配置密钥登陆</h2>
<p>通过修改 SSH 的配置文件,为服务器预先配置好各主机的私钥和别名,之后就可以方便快捷地登陆服务器。</p>
<p>修改 <code>~/.ssh/config</code> 文件,格式如下:</p>
<pre tabindex="0"><code>Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_rsa
</code></pre><p>上例配置 SSH 默认使用私钥 <code>~/.ssh/id_rsa</code> 进行连接。如果远端服务器已经事先将 <code>~/.ssh/id_rsa.pub</code> 添加到对应用户的 <code>~/.ssh/authorized_keys</code> 文件中,那么在本地执行命令 <code>$ ssh user@example.com</code> 后就可以自动免密登陆主机 <code>example.com</code></p>
<h2 id="配置主机别名">配置主机别名</h2>
<p>对于个别不同的服务器配置,我们可以继续在 <code>~/.ssh/config</code> 文件中添加配置:</p>
<pre tabindex="0"><code>Host test
Hostname localhost.test
Port 1234
IdentityFile ~/.ssh/test_rsa
User ubuntu
</code></pre><p>上例配置主机 <code>localhost.test:1234</code> 使用用户 <code>ubuntu</code> 和私钥 <code>~/.ssh/test_rsa</code> 进行连接。如果不配置 <code>IdentityFile</code> 则会提示输入密码才能登陆。</p>
<p>可以看到上述配置的 <code>Host</code> 项即为 SSH 连接的别名。该例中 <code>Host</code> 值为 <code>test</code>,那么我们在需要 SSH 连接主机 <code>localhost.test:1234</code> 的时候就可以直接执行命令立即免密登陆远端主机:</p>
<pre tabindex="0"><code>ssh test
</code></pre><h2 id="命令别名">命令别名</h2>
<p>如果不想这么麻烦,也可以通过设置命令别名来达到目的</p>
<p>修改 <code>~/.bash_profile</code> 文件,并根据服务器配置添加不同的命令别名:</p>
<pre tabindex="0"><code>alias myserver="ssh user@example.com"
alias myserver1234="ssh user@localhost.test -p 1234"
alias myserver="ssh user@remote.test -i ~/.ssh/id_rsa"
</code></pre><p>需要 SSH 连接主机 <code>localhost.test:1234</code> 的时候执行命令 <code>$ myserver1234</code> 即可。</p>
<p>真是好方便呢!</p>
《精通正则表达式》学习笔记(四)
https://acuario.xyz/posts/mastering-regex-summary-4/
2023-09-27T18:25:39+00:00
2019-07-23T21:44:11+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<blockquote>
<p>编写巧妙的正则表达式不仅仅是一种手艺(skill) 而且还是一种艺术(art)。</p>
</blockquote>
<h2 id="正则引擎的平衡法则">正则引擎的平衡法则</h2>
<ul>
<li>只匹配期望的文本,排除不期望的文本。</li>
<li>易于控制和理解。</li>
<li>使用NFA引擎时必须保证效率——能够匹配时立即返回匹配结果,不能匹配时尽快报告匹配失败。</li>
</ul>……
<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<blockquote>
<p>编写巧妙的正则表达式不仅仅是一种手艺(skill) 而且还是一种艺术(art)。</p>
</blockquote>
<h2 id="正则引擎的平衡法则">正则引擎的平衡法则</h2>
<ul>
<li>只匹配期望的文本,排除不期望的文本。</li>
<li>易于控制和理解。</li>
<li>使用NFA引擎时必须保证效率——能够匹配时立即返回匹配结果,不能匹配时尽快报告匹配失败。</li>
</ul>
<h2 id="实例">实例</h2>
<h3 id="匹配-ip-地址">匹配 IP 地址</h3>
<ul>
<li>「<code>[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*</code>」会匹配 <code>and then ......</code></li>
<li>「<code>^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$</code>」字符组书写重复</li>
<li>「<code>^\d+\.\d+\.\d+\.\d+$</code>」会匹配非 IP 地址文本如:<code>1234.5678.9101112.131415</code></li>
<li>「<code>^\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d$</code>」数字部分匹配不够灵活,仅能匹配 3 位数字</li>
<li>下面三个表达式会匹配非法 IP 地址数字 <code>999</code>
<ul>
<li>「<code>^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$</code>」</li>
<li>「<code>\d\d?\d?.\d\d?\d?.\d\d?\d?.\d\d?\d?$</code>」</li>
<li>「<code>\d(\d\d?)?.\d(\d\d?)?.\d(\d\d?)?.\d(\d\d?)?$</code>」</li>
</ul>
</li>
<li>分析 IP 地址结构可以得出以下规律:
<ul>
<li>只包含一个或两个数字的字段,无需考虑合法性,即「<code>\d|\d\d</code>」。</li>
<li><code>0</code> 或 <code>1</code> 开头的三位数(<code>000</code>-<code>199</code>)都合法。即「<code>[01]\d\d</code>」。</li>
<li><code>2</code> 开头的三位数字,第二位数字小于 <code>5</code> 则合法(<code>255</code>),即「<code>2[0-4]\d</code>」。</li>
<li>若第二位数字是 <code>5</code>,第三位数字就必须小于 <code>6</code>(<code>256</code>),即「<code>25[0-5]</code>」。</li>
<li>上述结果为「<code>\d|\d\d|[01]\d\d|2[0-4]\d|25[0-5]</code>」</li>
<li>合并前三个多选分支「<code>\d|\d\d|[01]\d\d</code>」为「<code>[01]?\d\d?</code>」</li>
<li>综上,一个 IP 地址数字的表达式结果为「<code>[01]?\d\d?|2[0-4]\d|25[0-5]</code>」</li>
</ul>
</li>
<li>匹配一个 IP 地址的表达式为:</li>
</ul>
<pre tabindex="0"><code>「^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$」
</code></pre><ul>
<li>在「<code>^</code>」后添加环视「<code>(?!0+\.0+\.0+\.0+$)</code>」来避免匹配 <code>0.0.0.0</code></li>
<li>在表达式首尾添加环视「<code>(?<![\w.])</code>...<code>(?![\w.])</code>」或使用「<code>(^| )</code>...<code>( |$)</code>」来保证匹配文本前后不出现「<code>[\w.]</code>」能匹配的字符,避免匹配嵌套型字符 <code>1.2.3.4.5.6</code> 中的 <code>1.2.3.4</code> 等类似 IP 地址的文本</li>
<li>某些时候,处理各种极端情形会降低投入产出比。更合适的做法是<strong>不依赖正则表达式完成全部工作,善用其他工具辅助验证</strong>。</li>
</ul>
<h3 id="处理文件名">处理文件名</h3>
<p>文本:<code>/usr/local/bin/gcc</code><br>
期望:<code>gcc</code></p>
<ol>
<li>去掉文件名开头的路径<br>
RegEx:<code>^.*/</code><br>
释义:使用匹配优先(贪婪)特性,匹配一整行,然后回溯到最后的斜线</li>
</ol>
<ul>
<li>若匹配一个恰好没有斜线的字符串,正则引擎会在字符串的起始位置开始搜索。「<code>.*</code>」抵达字符串的末尾,但不断回退,直到最后它交还了匹配的所有字符,仍然无法匹配。此时,正则引擎得知<strong>在字符串的起始位</strong>不存在匹配。</li>
<li>之后传动装置开始工作,从第 2 个字符开始,依次尝试匹配整个正则表达式,在字符串的每个位置进行扫描回溯。若字符串很长,就可能存在大量的回溯(DFA 不存在这个问题)。</li>
<li>几乎所有以「<code>.*</code>」开头的正则表达式,在某个字符串的起始位置不能匹配,也就不能在其他任何位置匹配,它只会在字符串的起始位置尝试一次。</li>
<li>在正则表达式中写明开头位置的匹配规则更明智一些。</li>
</ul>
<ol start="2">
<li>从路径中获取文件名<br>
RegEx:<code>([^/]*)$</code><br>
释义:在结尾设置一个锚点,忽略路径,从最后一个斜线开始匹配所有内容。</li>
</ol>
<ul>
<li>该表达式的唯一要求是字符串有 <code>$</code> 能够匹配的结束位置</li>
<li>在 NFA 中,该表达式的效率很低,要进行 40+ 次回溯。</li>
</ul>
<ol start="3">
<li>所在路径和文件名<br>
RegEx:<code>^(.*)/(.*)$</code><br>
释义:使用 <code>$1</code> 和 <code>$2</code> 来提取所在路径和文件名。第一个「<code>.*</code>」先捕获所有文本,不给「<code>/</code>」和 <code>$2</code> 留下任何字符,在尝试匹配「<code>/(.*)$</code>」时发生的回溯会把“交还的”部分留给后面的「<code>.*</code>」。</li>
</ol>
<h3 id="匹配对称的括号">匹配对称的括号</h3>
<ol>
<li>「<code>\(.*\)</code>」 匹配括号及括号内部的任何字符。</li>
<li>「<code>\([^)]*\)</code>」 匹配从一个开括号到最近的闭括号。</li>
<li>「<code>\([^()]*\)</code>」 匹配从一个开括号到最近的闭括号,但是不容许其中包含开括号。</li>
</ol>
<ul>
<li>上下述三个表达式用于匹配带括号的文本内容,匹配结果如图</li>
</ul>
<p><img src="https://i.loli.net/2019/07/17/5d2e05fe2848445405.png" alt="匹配带括号的文本"></p>
<ul>
<li>为解决<strong>正则表达式无法匹配任意深度的嵌套结构</strong>的问题,可以用正则表达式来匹
配特定深度的嵌套括号,但不是任意深度的嵌套括号。</li>
<li>处理单层嵌套的正则表达式是:「<code>\([^()]*(\([^()]*\)[^()]*)*\)</code>」</li>
</ul>
<h3 id="匹配浮点数">匹配浮点数</h3>
<ul>
<li>「<code>-?[0-9]*\.?[0-9]*</code>」会匹配 <code>-.0</code></li>
<li>「<code>-?[0-9]*\.?[0-9]*</code>」会产生空匹配(匹配没有任何必须的元素),如 <code>this has no number</code>、<code>nothing here</code></li>
<li><strong>把真正意图表达清楚</strong>非常重要:一个浮点数必须要有至少一位数字,否则就不是一个合法的值。</li>
<li>「<code>-?[0-9]+</code>」用于限定浮点数含有数字的特性</li>
<li>「<code>(\.[0-9]*)?</code>」用于限定浮点数的<em>小数点</em>和<em>小数部分</em></li>
<li>综上,「<code>-?[0-9]+(\.[0-9]*)?</code>」即可用于匹配浮点数而不匹配空字符,即不产生<strong>空匹配</strong></li>
</ul>
<h3 id="匹配分隔符之内的文本">匹配分隔符之内的文本</h3>
<p>文本:<code>a passport needs a "2\"x3\" likeness" of the holder</code><br>
期望:<code>"2\"x3\" likeness"</code></p>
<ul>
<li>匹配分隔符之内的文本的主要步骤:
<ol>
<li>匹配起始分隔符(opening delimiter)。</li>
<li>匹配正文(main text,即结束分隔符之前的所有文本)。</li>
<li>匹配结束分隔符。</li>
</ol>
</li>
<li>匹配开始和结束分隔符很容易,但匹配正文的时不能超越结束分隔符:
<ul>
<li>匹配非引号内容:「<code>[^"]</code>」</li>
<li>匹配转义的反斜线需要使用环视:「<code>(?<=\\)"</code>」</li>
<li>综上得出的表达式为「<code>"([^"]|(?<=\\)")*"</code>」,此时可以匹配 <code>2\"x3\"</code></li>
</ul>
</li>
</ul>
<p>文本:<code>"/-|-\\" or "[^-^]"</code><br>
期望:<code>"/-|-\\"</code><br>
RegEx:<code>"([^"]|(?<=\\)")*"</code><br>
结果:<code>"/-|-\\" or "</code></p>
<ul>
<li>第一个闭引号之前存在一个反斜线,该反斜线本身是被转义的,其后的引号是表示引用文本的结束。逆序环视无法识别这个被转义的反斜线。</li>
<li>匹配的位于开始分隔符和结東分隔符之间的文本可以包括转义的字符「<code>\\.</code>」,也可以包括非引号的任何字符「<code>[^"]</code>」。</li>
<li>综上得出的表达式为「<code>"(\\.|[^"])*"</code>」</li>
<li>匹配优先和忽略优先都期望获得匹配,如果找不到结束的引号,它就会回溯,从而降低性能。</li>
<li>如果回溯会导致不期望,与多选结构有关的匹配结果,可能是因为任何成功的匹配都不过是多选分支的排列顺序造成的偶然结果,</li>
<li>如果有<strong>占有优先量词</strong>或者是<strong>固化分组</strong>,那么这个正则表达式可以被持续优化以提升性能(特别是对于 NFA)</li>
</ul>
<h3 id="去除文本首尾的空白字符">去除文本首尾的空白字符</h3>
<ol>
<li>去除文本首部的空白字符「<code>s/^\s+//</code>」<br>
去除文本末尾的空白字符「<code>s/\s+$/</code>」</li>
<li>去除文本首尾空白字符的表达式:「<code>s/\s*(.*?)\s*$/$1/s</code>」<br>
该表达式因为忽略优先约束的点号每次应用时都要检查「<code>\s*$</code>」导致大量回溯,严重影响效率。</li>
<li>去除文本首尾空白字符的表达式:「<code>s/^\s*((?:.*\S)?)\s*$/$1/s</code>」后面的「<code>\S</code>」强迫回溯直到找到一个非空字符,把剩下的空白字符留给最后的「<code>\s*$</code>」,捕获括号之外的内容。</li>
</ol>
<h2 id="html-相关范例">HTML 相关范例</h2>
<h3 id="匹配-html-tag">匹配 HTML Tag</h3>
<p>RegEx:<code><("[^"]*"|'[^']*'|[^'">])*></code><br>
释义:
<img src="https://i.loli.net/2019/07/20/5d31ec5ad68a949796.png" alt="匹配 HTML Tag"></p>
<ul>
<li>引用字符串可能为空(例如 <code>alt=""</code>), 所以最开始的两个多选分支的引号中使用「<code>*</code>」而非「<code>+</code>」。</li>
<li>NFA 引擎下,多选分支之间不存在重复,所以最后的「<code>></code>」无法匹配是产生的回溯是不需要的,可使用非捕获型括号改写表达式以提高效率。</li>
</ul>
<h3 id="匹配-html-link">匹配 HTML Link</h3>
<p>文本:<code>...<a href="http://www.oreilly.com">O'Reilly Media</a>...</code>
期望:<code>http://www.oreilly.com</code> 和 <code>O'Reilly Media</code><br>
RegEx:<code>\b HRFF\s* = \s*(?:"([^"]*)"|'([^']*)'|([^'">\S]+))</code><br>
释义:
<img src="https://i.loli.net/2019/07/20/5d31f0a71ac2934742.png" alt="匹配 HTML Link"></p>
<h3 id="校验-http-url">校验 HTTP URL</h3>
<p>将 URL 地址分解为主机名(hostname)和路径(path)两部分。</p>
<pre tabindex="0"><code>^http:// # 匹配协议
([^/:]+) # 捕获主机名
(:(\d+))? # 匹配端口号(可能没有)
(/.*)?$ # 捕获路径
</code></pre><h3 id="提取-url">提取 URL</h3>
<p>从纯文本中提取 URL 的正则表达式框架如下:
<img src="https://i.loli.net/2019/07/22/5d34a44a170a511410.png" alt="提取纯文本中的URL"></p>
<h3 id="几个保持数据协调性的原则">几个保持数据协调性的原则</h3>
<p>手动保持正则引擎的协调,才能忽略不需要的文本。有时为了提高表达式的效率,应该选择跳过不需要的文本,而非使用正向思维直接匹配目标文本。</p>
<ol>
<li>根据期望保持匹配的协调性<br>
合理使用忽略优先量词,在后面的表达式失败之前,优先忽略容易引起大范围匹配成功的匹配操作。跳过我们希望跳过的文本而进行匹配。</li>
<li>不匹配时也应当保证协调性</li>
<li>使用「<code>\G</code>」保证协调<br>
「<code>\G</code>」用于匹配上一次匹配结束的位置。</li>
</ol>
《精通正则表达式》学习笔记(三)
https://acuario.xyz/posts/mastering-regex-summary-3/
2023-09-27T18:25:39+00:00
2019-07-14T23:27:11+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="正则引擎的分类">正则引擎的分类</h2>
<p>正则引擎主要分为 3 类:</p>
<ol>
<li>DFA(符合或不符合 POSIX 标准的都属此类)</li>
<li>传统型 NFA</li>
<li>POSIX NFA</li>
</ol>
<table>
<thead>
<tr>
<th>引擎类型</th>
<th>程序</th>
<th>忽略优先量词(懒惰)</th>
<th>捕获型括号</th>
<th>回溯</th>
</tr>
</thead>
<tbody>
<tr>
<td>DFA</td>
<td><code>awk</code>(大多数版本)、<code>egrep</code>(大多数版本)、<code>flex</code>、<code>lex</code>、MySQL、Procmail</td>
<td>不支持</td>
<td>不支持</td>
<td>不支持</td>
</tr>
<tr>
<td>传统型 NFA</td>
<td>GNU Emacs、Java、<code>grep</code>(大多数版本)、<code>less</code>、<code>more</code>、.NET 语言、PCRE library、Perl、PHP(所有三套正则库)、Python、Ruby、sed(大多数版本)、<code>vi</code></td>
<td>支持</td>
<td>支持</td>
<td>支持,但性能差</td>
</tr>
<tr>
<td>POSIX NFA</td>
<td><code>mawk</code>、Mortice Kern Systems'utilities、GNU Emacs(明确指定时使用)</td>
<td>不支持</td>
<td>支持</td>
<td>支持,但性能差</td>
</tr>
<tr>
<td>DFA/NFA 混合</td>
<td>GNU <code>awk</code>、GNU <code>grep/egrep</code>、Tcl</td>
<td>支持</td>
<td>支持</td>
<td>DFA 支持</td>
</tr>
</tbody>
</table>
<ul>
<li>判断是否传统型 NFA:是否支持忽略优先量词(懒惰)。使用正则表达式 <code>nfa|nfa not</code> 来匹配字符串 <code>nfa not</code>,如果只匹配了 <code>nfa</code>,这就是传统型 NFA。如果整个 <code>nfa not</code> 都能匹配,则此引擎要么是 POSIXNFA,要么是 DFA。</li>
</ul>……
<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="正则引擎的分类">正则引擎的分类</h2>
<p>正则引擎主要分为 3 类:</p>
<ol>
<li>DFA(符合或不符合 POSIX 标准的都属此类)</li>
<li>传统型 NFA</li>
<li>POSIX NFA</li>
</ol>
<table>
<thead>
<tr>
<th>引擎类型</th>
<th>程序</th>
<th>忽略优先量词(懒惰)</th>
<th>捕获型括号</th>
<th>回溯</th>
</tr>
</thead>
<tbody>
<tr>
<td>DFA</td>
<td><code>awk</code>(大多数版本)、<code>egrep</code>(大多数版本)、<code>flex</code>、<code>lex</code>、MySQL、Procmail</td>
<td>不支持</td>
<td>不支持</td>
<td>不支持</td>
</tr>
<tr>
<td>传统型 NFA</td>
<td>GNU Emacs、Java、<code>grep</code>(大多数版本)、<code>less</code>、<code>more</code>、.NET 语言、PCRE library、Perl、PHP(所有三套正则库)、Python、Ruby、sed(大多数版本)、<code>vi</code></td>
<td>支持</td>
<td>支持</td>
<td>支持,但性能差</td>
</tr>
<tr>
<td>POSIX NFA</td>
<td><code>mawk</code>、Mortice Kern Systems'utilities、GNU Emacs(明确指定时使用)</td>
<td>不支持</td>
<td>支持</td>
<td>支持,但性能差</td>
</tr>
<tr>
<td>DFA/NFA 混合</td>
<td>GNU <code>awk</code>、GNU <code>grep/egrep</code>、Tcl</td>
<td>支持</td>
<td>支持</td>
<td>DFA 支持</td>
</tr>
</tbody>
</table>
<ul>
<li>判断是否传统型 NFA:是否支持忽略优先量词(懒惰)。使用正则表达式 <code>nfa|nfa not</code> 来匹配字符串 <code>nfa not</code>,如果只匹配了 <code>nfa</code>,这就是传统型 NFA。如果整个 <code>nfa not</code> 都能匹配,则此引擎要么是 POSIXNFA,要么是 DFA。</li>
</ul>
<h2 id="匹配的基础">匹配的基础</h2>
<p>普适规则:</p>
<ol>
<li>优先选择最左端(最靠开头)的匹配结果。</li>
<li>标准的匹配量词(<code>*</code>、<code>+</code>、<code>?</code> 和 <code>{m,n}</code>)是匹配优先(greedy,贪婪)的。</li>
</ol>
<ul>
<li>标准匹配量词的结果“可能”并非所有可能中最长的,但它们总是尝试匹配尽可能多的字符,直到<strong>匹配上限</strong>为止。如果最终结果并非该表达式的所有可能中最长的,原因肯定是匹配字符过多导致匹配失败。</li>
<li>「<code>.*</code>」永远不会失败,因为“不匹配任何字符”也是「<code>.*</code>」的可能结果之一。</li>
<li>「<code>(.*).*</code>」结果没有变化。开头的「<code>.*</code>」(括号中的)会霸占整个标题的文本,而不给第二个「<code>.*</code>」留下任何字符。而第二个「<code>.*</code>」的匹配失败并不要紧,因为「<code>.*</code>」不匹配任何字符也能成功。如果我们给第二个「<code>.*</code>」也加上括号,<code>$2</code>将会是空白。</li>
<li>表达式中的某些部分可能“<strong>强迫</strong>”之前匹配优先的部分“释放”(或者说“交还(unmatch)”) 某些字符。例如:「<code>^.*([0-9][0-9])</code>」将“<strong>强迫</strong>”「<code>.*</code>」交还两个数字使得匹配成功。</li>
<li>多个贪婪贪婪量词之间遵循「<strong>先来先服务</strong>」原则。例如:「<code>^.*([0-9]+)</code>」试图匹配 <code>copyright 2003</code> 时,「<code>([0-9]+)</code>」只能匹配到「3」而非「2003」,在该例子中,首先服务「<code>^.*</code>」,使其满足最贪婪的要求,然后才服务「<code>([0-9]+)</code>」。</li>
</ul>
<h2 id="表达式主导与文本主导">表达式主导与文本主导</h2>
<ul>
<li>DFA:确定型有穷自动机</li>
<li>NFA:非确定型有穷自动机</li>
</ul>
<blockquote>
<p>NFA 以表达式本身为依据,进行匹配尝试,DFA 以匹配文本为依据,观察子表达式是否匹配成功。</p>
</blockquote>
<ul>
<li>NFA 引擎:表达式主导(regex-directed)——表达式中的控制权在不同的元素之间转换。正则表达式每次检查一部分(由引擎查看表达式的一部分),同时检查“当前文本(current text)”是否匹配表达式的当前部分。如果是,则继续表达式的下一部分,如此继续,直到表达式的所有部分都能匹配,即整个表达式能够匹配成功。</li>
<li>DFA 引擎:文本主导(text-directed)——在扫描字符串时,会记录“当前有效(currently in the works)”的所有匹配可能。</li>
<li>DFA引擎在扫描字符串时,会记录“当前有效(currently in the works)”的所有匹配可能。</li>
<li>DFA 扫描的字符串中的每个字符都对引擎进行了控制。在本例中,某个未完成的匹配也许是任意多个(只要可行)匹配的开始。不合适的匹配可能在扫描后继文字时会被去除。文本中出现的某个字符会令所有处理中的匹配可能失效,就会返回某个之前保留的完整匹配。如果不存在这样的完整匹配,则要报告在当前位置无法匹配。</li>
</ul>
<h3 id="nfa-和-dfa-比较">NFA 和 DFA 比较</h3>
<ul>
<li>一般情况下,文本主导的 DFA 引擎要快一些。正则表达式主导的 NFA 引擎,因为需要对同样的文本尝试不同的子表达式匹配,可能会浪费时间。</li>
<li>在 NFA 的匹配过程中,目标文本中的某个字符可能会被正则表达式中的不同部分重复检测(甚至有可能被同一部分反复检测)。</li>
<li>DFA 引擎则是确定型的(deterministic)——目标文本中的每个字符只会检查(最多)一遍。</li>
<li>DFA 引擎会同时记录所有的匹配选择,所以不同表达式最终能够捕获的文本相同,在写法上的差异并无意义,选择哪一个表达式并无区别。</li>
<li>DFA 匹配很迅速、一致。</li>
</ul>
<h2 id="回溯">回溯</h2>
<ul>
<li>
<p>如果正则表达式中余下的部分最终匹配失败,引擎会知道需要<strong>回溯</strong>到之前做出选择的地方,选择其他的备用分支继续尝试。</p>
</li>
<li>
<p>回溯仅发生于 NFA 引擎执行匹配时,这是由 NFA 的特性导致——NFA 引擎是表达式主导,在每次扫描文本后都检测是否满足量词和多选结构,如果不满足且无待扫描文本,则会一次又一次「撤销」扫描,取出最近一次满足匹配的结果。这个回滚动作就是「回溯」。</p>
</li>
<li>
<p>回溯的机制类似于面包屑 / 压栈(LIFO,Last In First Out,后进先出),也可以说面包屑即为压栈存储的一个个<strong>备用状态</strong>。</p>
<p>举个栗子,用「<code>[0-9+]</code>」来匹配 <code>a 1234 num</code> 的过程中:</p>
<p><img src="https://i.loli.net/2019/06/21/5d0c38074ab5f56669.png" alt=""></p>
<p>锚点从上到下形如面包屑,在匹配失败时回到上一级继续尝试匹配。
四个锚点的的状态都会作为保留状态记录下来,依次查看最长的匹配文本,并在匹配失败时一个接一个回溯回来。</p>
</li>
<li>
<p>回溯机制不但需要重新计算正则表达式和文本的对应位置,也需要维护括号内的子表达式所匹配文本的状态。</p>
</li>
<li>
<p>在匹配过程中,每次回溯都把当前状态中正则表达式的对应位置指向括号之前。</p>
</li>
<li>
<p>回溯对括号的这种处理,不但需要同时维护 <code>$1</code> 的状态,也会影响匹配的效率。</p>
</li>
<li>
<p>由星号(或其他任何匹配优先量词)限定的部分不受后面元素影响,而只是匹配尽可能多的内容。</p>
</li>
<li>
<p>忽略优先的匹配(懒惰)的原因在于,其首先考虑尝试忽略,如「<code>b??</code>」中的懒惰量词「<code>??</code>」会首先<strong>匹配零个</strong>文本 <code>b</code>(注意并不是<strong>不匹配</strong>)</p>
</li>
<li>
<p>简单说,懒惰量词就是匹配其能力的下限,比如「<code>b{3,8}?</code>」在匹配 <code>bbbbbbb</code> 时只匹配 3 个 <code>b</code>;「<code>b+?</code>」在匹配 <code>bbbbbbb</code> 时只匹配 1 个 <code>b</code>。</p>
</li>
</ul>
<h2 id="关于贪婪懒惰和回溯的要点">关于贪婪、懒惰和回溯的要点</h2>
<ul>
<li>
<p>由于「<code>*</code>」是贪婪的量词,所以在使用时还需谨慎,不能过分依赖。举个栗子:
文本:<code>The name "McDonald's" is said "makudonarudo" in Japanese.</code></p>
<ol>
<li>
<p>RegEx:<code>".*"</code><br>
结果:<code>"McDonald's" is said "makudonarudo"</code>
释义:贪婪量词尽可能多地进行匹配</p>
</li>
<li>
<p>RegEx:<code>"[^"]*"</code><br>
结果:<code>"McDonald's"</code>
释义:「<code>[^"]</code>」尽可能多地匹配非<code>"</code>的字符,即<code>"</code>前的字母</p>
</li>
</ol>
</li>
<li>
<p>善用<strong>懒惰量词</strong>解决成对标签的问题。举个栗子:
文本:<code>...<B>Billions</B> and <B>Zillions</B> of suns....</code>
期望:<code><B>Billions</B></code></p>
<ol>
<li>
<p>RegEx:<code><B>[^</B>]</B></code><br>
结果:匹配失败
释义:<code>[]</code>是字符范围元字符,无法表达<code>非</B></code>的含义,可以使用环视功能进行匹配</p>
</li>
<li>
<p>RegEx:<code><B>.*?</B></code><br>
结果:<code><B>Billions</B></code>
释义:「<code>*?</code>」为懒惰量词,可以尽可能少地匹配文本</p>
</li>
</ol>
</li>
<li>
<p>懒惰量词有时在处理成对符号时并不完美。举个栗子:
文本:<code>...<B>Billions and <B>Zillions</B> of suns....</code>
期望:<code><B>Zillions</B></code></p>
<ol>
<li>
<p>RegEx:<code><B>.*?</B></code><br>
结果:<code><B>Billions and <B>Zillions</B></code>
释义:「<code>.*?</code>」会匹配左边的<code><B></code>标签,这是不满足期望的,可以使用<strong>排除环视</strong>功能进行匹配</p>
</li>
<li>
<p>RegEx:<br>
<img src="https://i.loli.net/2019/07/04/5d1e1c173fa1470167.png" alt="">
结果:<code><B>Billions</B></code></p>
</li>
<li>
<p>RegEx:<br>
<img src="https://i.loli.net/2019/07/04/5d1e1c6c2cb0387976.png" alt="">
结果:<code><B>Billions</B></code></p>
</li>
</ol>
</li>
<li>
<p>有一些问题是贪婪和懒惰都无法解决的问题,举个例子:
文本:<code>1.62500000002828</code>,<code>9.43</code>,<code>27.625</code>
期望:替换过长小数为三位小数 <code>1.625</code>,<code>9.43</code>,<code>27.625</code></p>
<ol>
<li>
<p>RegEx:<code>$prive =~ s/(\.\d\d[1-9]?)\d*/$1/;</code><br>
结果:<code>$1 = 1.625</code>
释义:对于匹配三位小数,此表达式效率还不够高,部分匹配过程存在浪费</p>
</li>
<li>
<p>RegEx:<code>$prive =~ s/(\.\d\d[1-9]?)\d+/$1/;</code><br>
结果:<code>$1 = 1.625</code>(正常替换),<code>$1 = 9.43</code> (不替换),<code>$1 = 27.62</code>
释义:「<code>\.\d\d</code>」匹配了 <code>27.62</code>,「<code>\d+</code>」匹配了 <code>5</code>,「<code>[1-9]?</code>」为可选分支,优先级别比「<code>\d+</code>」低,不进行任何匹配,于是最终导致 <code>27.625</code> 被替换为 <code>27.62</code></p>
</li>
</ol>
</li>
<li>
<p>在<strong>只有一条可能的匹配路径时</strong>,使用<em>贪婪</em>和<em>懒惰</em>量词的正则表达式对结果无影响,只是因其尝试路径的次序不同,引擎尝试匹配的次数不同,即<strong>效率不同</strong>。</p>
</li>
</ul>
<h2 id="固化分组">固化分组</h2>
<ul>
<li>在固化分组「<code>(?>……)</code>」匹配结束时,它已经匹配的文本已经固化为一个单元,只能作为整体而保留或放弃。回溯永远也不能选择其中的状态。举个例子:「<code>(\.\d\d(?>[1-9]?))\d+</code>」中固化分组「<code>(?>[1-9]?)</code>」使得 <code>.625</code> 末尾的 5 会遭遇 「<code>[1-9]?</code>」的固化匹配,然后再「<code>\d+</code>」需要回溯时匹配失败,从而导致 <code>.625</code> 整个文本匹配失败,从而不被处理,提升执行效率。</li>
<li>贪婪和懒惰影响检测顺序,固化分组影响备用状态(面包屑)的取舍。</li>
<li>[<code>(?>.*?)</code>」是一个相当复杂的正则表达式,它永远无法匹配任何字符。「<code>.*?</code>」是「<code>.*</code>」的忽略优先(懒惰)表示,它限定的是一个点号,所以首选的分支是忽略点号,把匹配点号的状态保留下来备用。但该备用状态马上又会因为匹配退出了固化分组而被放弃。</li>
<li>「<code>^\w+:</code>」无法匹配 <code>Subject</code>,但正则表达式必须从末尾依次向前尝试匹配各种备用状态后才能得出匹配失败的结论。使用固化分组正则表达式「<code>^(?>\w+):</code>」将在尝试「<code>:</code>」匹配失败后直接抛弃固化分组内容「<code>\w+</code>」,即只需尝试 1 次匹配便得出匹配失败结论。<strong>大大提高匹配效率。</strong></li>
</ul>
<h2 id="环视">环视</h2>
<ul>
<li>环视结构的匹配尝试结束,它就不会留下任何备用状态。</li>
<li>在肯定环视中使用捕获括号,就能模拟实现固化分组和占有优先量词。「<code>(?>regex)</code>」可以用「<code>(?=(regex))\1</code>」来模拟。举个栗子:
<ul>
<li>「<code>(?>\w+):</code>」为固化分组表达式</li>
<li>「<code>^(?=(\w+))\1:</code>」为环视表达式,环视中的「<code>\w+</code>」是贪婪匹配的,匹配整个单词。当环视结束之后,备用状态都会被放弃(和固化分组一样)。但与固化分组不同:虽然此时捕获了单词,但它不是全局匹配的一部分。「<code>\1</code>」的使用是为了把匹配从这个单词结束的位置进行下去。</li>
</ul>
</li>
</ul>
<h2 id="多选结构">多选结构</h2>
<ul>
<li>对 NFA 来说,多选结构既<strong>不是匹配优先的</strong>,也<strong>不是忽略优先的</strong>,而是<strong>按顺序排列</strong>的。</li>
<li>对 DFA 来说,多选结构匹配所有多选分支中能匹配最多文本的那个。</li>
<li>如果多选分支是<strong>按顺序排列</strong>的。,而能够匹配同样文本的多选分支又<strong>不只一个</strong>,就要小心安排多选分支的<strong>先后顺序</strong>。</li>
</ul>
<p>文本:<code>Jan 31 is Dad's birthday</code>
期望:<code>Jan 31</code></p>
<ol>
<li>
<p>RegEx:<code>Jan (0?[1-9]|[12][0-9]|3[01])</code>
结果:<code>Jan 3</code>
释义:「<code>0?</code>」不会匹配成功,但后续的「<code>[0-9]</code>」会匹配 <code>3</code>,此时完成所有匹配需求,故匹配成功。</p>
</li>
<li>
<p>RegEx:<code>Jan ([12][0-9]|3[01]|0?[1-9])</code>
RegEx:<code>Jan (31|[123]0|[012?[1-9]])</code>
结果:<code>Jan 31</code>
释义:上述两个 RegeEx 的多选结构顺序保证了匹配的内容与期望相符</p>
</li>
<li>
<p>RegEx:<code>Jan (0[1-9]|[12][0-9]?|3[01]?|[4-9])</code>
结果:<code>Jan 31</code>
释义:上述多选结构不受内部多选分支的顺序影响,均可匹配成功</p>
</li>
</ol>
<h2 id="nfadfa-和-posix">NFA、DFA 和 POSIX</h2>
<p>NFA 和 DFA 引擎理应匹配相同文本,提供相同功能。但在实际中,因为人们需要更强的功能,更具表达能力的正则表达式,它们各自的表达式语意(解析方式)发生了变化。</p>
<h3 id="最左最长规则">最左最长规则</h3>
<ul>
<li>如果传动装置在文本的某个特定位置启动 DFA 引擎,而在此位置又有一个或多个匹配的可能,DFA 就会选择这些可能中最长的。</li>
<li>POSIX 标准规定,如果在字符串的某个位置存在多个可能的匹配,应当返回的是最长的匹配。</li>
</ul>
<h3 id="速度和效率">速度和效率</h3>
<ul>
<li>POSIX NFA 需要进行更多的回溯,尝试正则表达式的所有变体。所以表达式的差异会极大影响其匹配的效率。</li>
<li>DFA 引擎用更多时间和空间来换取匹配效率。</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>DFA</th>
<th>NFA</th>
</tr>
</thead>
<tbody>
<tr>
<td>预编译阶段</td>
<td>优化措施的效果更好</td>
<td>编译更快,所需内存更少</td>
</tr>
<tr>
<td>匹配速度</td>
<td>与表达式无关</td>
<td>与表达式有关</td>
</tr>
<tr>
<td>匹配速度</td>
<td></td>
<td>NFA 尝试表达式的所有变体后才报告匹配失败,POSIX NFA 尝试匹配最长文本</td>
</tr>
<tr>
<td>匹配结果</td>
<td>返回最左最长文本</td>
<td>NFA 返回最左最长文本 / 其他文本</td>
</tr>
<tr>
<td>匹配能力</td>
<td></td>
<td>1. 支持捕获括号内的子表达式的文本(eg. 反向引用 / 后匹配信息)</td>
</tr>
<tr>
<td>匹配能力</td>
<td></td>
<td>2. 支持环视和其他零长度确认</td>
</tr>
<tr>
<td>匹配能力</td>
<td></td>
<td>3. 支持懒惰量词和多选结构</td>
</tr>
<tr>
<td>匹配能力</td>
<td></td>
<td>4. 支持贪婪量词和固化分子</td>
</tr>
<tr>
<td>实现难度</td>
<td></td>
<td>实现简单</td>
</tr>
</tbody>
</table>
播客札记(三):剧透&外卖
https://acuario.xyz/others/podcast-note-3/
2023-09-27T18:25:39+00:00
2019-06-07T13:04:59+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="八分-第-80-期--剧透的思考练习言论自由还是道德错误">八分 第 80 期 | 剧透的思考练习:言论自由还是道德错误?</h2>
<p><a href="https://overcast.fm/+Oh0W-o4Pc">Episode Archive</a></p>
<ul>
<li>
<p>剧透的伦理学基础:功利主义(效用主义)。</p>
</li>
<li>
<p>功利主义含义:所谓最大善的计算则必须依靠此行为所涉及的每个个体之苦乐感觉的总和,其中每个个体都被视为具相同分量,且快乐与痛苦是能够换算的,痛苦仅是 “负的快乐”。判断一件事的好坏,依据就是其是否增进人类最大的善,即增加人类的总体快乐。</p>
</li>
<li>
<p>剧透带来的双成伤害:</p>
<ol>
<li>剧透减少了观影的悬疑性,破坏了观影过程的乐趣;</li>
<li>剧透破坏了观影前对影视作品的期待与喜悦。</li>
</ol>
</li>
<li>
<p>剧透的言论自由基础:卡尔·波普尔在《开放社会及其敌人》中提出的「宽容悖论」。</p>
</li>
<li>
<p>宽容悖论:</p>
<blockquote>
<p>无限的宽容必然导致宽容的消失。如果我们把无限的宽容延伸到那些不宽容的人身上,如果我们不准备捍卫宽容社会以抵抗不宽容的冲击,那么宽容将被摧毁,并且我们还将容忍他们。</p>
</blockquote>
</li>
</ul>……
<h2 id="八分-第-80-期--剧透的思考练习言论自由还是道德错误">八分 第 80 期 | 剧透的思考练习:言论自由还是道德错误?</h2>
<p><a href="https://overcast.fm/+Oh0W-o4Pc">Episode Archive</a></p>
<ul>
<li>
<p>剧透的伦理学基础:功利主义(效用主义)。</p>
</li>
<li>
<p>功利主义含义:所谓最大善的计算则必须依靠此行为所涉及的每个个体之苦乐感觉的总和,其中每个个体都被视为具相同分量,且快乐与痛苦是能够换算的,痛苦仅是 “负的快乐”。判断一件事的好坏,依据就是其是否增进人类最大的善,即增加人类的总体快乐。</p>
</li>
<li>
<p>剧透带来的双成伤害:</p>
<ol>
<li>剧透减少了观影的悬疑性,破坏了观影过程的乐趣;</li>
<li>剧透破坏了观影前对影视作品的期待与喜悦。</li>
</ol>
</li>
<li>
<p>剧透的言论自由基础:卡尔·波普尔在《开放社会及其敌人》中提出的「宽容悖论」。</p>
</li>
<li>
<p>宽容悖论:</p>
<blockquote>
<p>无限的宽容必然导致宽容的消失。如果我们把无限的宽容延伸到那些不宽容的人身上,如果我们不准备捍卫宽容社会以抵抗不宽容的冲击,那么宽容将被摧毁,并且我们还将容忍他们。</p>
</blockquote>
</li>
</ul>
<ul>
<li>穆勒认为,除非某个人的言论或行为伤害(肉体或利益受损)而非冒犯(情绪、尊严受损)到一个人,否则其言论或行为不应被任何力量禁止。</li>
<li>剧透是否是对肉体和精神的真实伤害?还是仅仅只是一种冒犯?</li>
<li>剧透与权利的关系:如果剧透者是创作者本人,其是否有权剧透?这一剧透行为是否有合理性?</li>
<li>剧透与历史的关系:历史作品是否可以剧透?</li>
<li>真正伟大的作品不惧怕剧透。类型文学 / 作品是不可被剧透的。</li>
<li>剧透的另一种观赏乐趣:心平气和地感受作品的细节。</li>
<li>互联网的出现为剧透文化带来的改变:电影预告片即是对剧透文化的利用。</li>
<li>希区柯克的《惊魂记》告诫观众请勿剧透,助长了影片本身的神秘性。</li>
</ul>
<hr>
<h2 id="翻电-special-vol02--如何看待外卖行业和我们的责任">翻电 Special VOL02 | 如何看待外卖行业和我们的责任?</h2>
<p><a href="https://overcast.fm/+GsFhie5AY">Episode Archive</a></p>
<h3 id="劳动异化理论">劳动异化理论</h3>
<ul>
<li>劳动者是否掌握生产资料</li>
<li>如果劳动者被劳动以外的要素强迫,且劳动目的不属于自己、劳动对象不是自己,则该劳动过程将出现劳动异化</li>
</ul>
<h3 id="外卖工作为何是劳动异化的极端">外卖工作为何是劳动异化的极端</h3>
<p>现代社会普遍存在劳动异化,外卖是劳动异化的极端例子:</p>
<ol>
<li>外卖的工作空间为社会飞地,工作时没有任何主要(固定)的社会空间,完全游离于世界之外;</li>
<li>外卖者对外交流的对象并不固定,且人际交流时间非常短暂。相比之下,出租车司机与乘客也有相对长时间的共处;</li>
<li>外卖工作不掌握任何生产资料,在社会生产链条中一无所有,没有任何生产实践。相比之下,风投工作亦是如此;</li>
<li>外卖工作不具备任何工作经验、技能的积累,纵使有产生了经验、技能,也很难复用到其他工作。</li>
</ol>
<h3 id="为何作为一个工作外卖依然有伦理风险">为何作为一个工作,外卖依然有伦理风险</h3>
<ul>
<li>社会底线不是维持社会成为一个好社会的标准,而是维持社会不崩溃的标准</li>
<li>外卖工作虽没有触及社会底线,但却是劳动异化最极端的状态。</li>
<li>「谁雇佣谁负责 / 谁施行谁负责」是缺乏说服力的,由自我需求产生的特定现实需要需求方承担社会责任。反例为儿童色情 / 毒品问题。</li>
</ul>
<h3 id="为何我们不是雇佣者也应该关注外卖">为何我们不是雇佣者也应该关注外卖</h3>
<ul>
<li>外卖需求建立在手机、互联网之上。消费者为了避免与人交流,产生了这样「过度的」需求,这样的需求是商品社会「方便主义」至上的后果,它把心理负担和成本转嫁到外卖者身上。没有买卖就没有伤害。</li>
<li>大众具有选择性的同理心。体谅和同理心的适用对象不应只限于特殊岗位,如公权力赋权的对象,比如消防员。</li>
<li>同理心的对象不应以利益绑定为标准。仅对利益共同体给与同理心是功利主义的,若长此以往,互助互利的社会风气将会逐渐消解。</li>
<li>由于存在实然和应然的问题,带着负罪感的作为至少比毫不反思和理解要好,尝试理解外卖工作的特殊性和其中存在的道德风险,胜过以方便主义理所应当享用外卖服务。</li>
</ul>
<h3 id="问题反思">问题反思</h3>
<p>主要的问题在于:</p>
<ol>
<li>要在多大程度上对马克思经济学的基本概念进行外延?</li>
<li>导致事情极端,不是一个因素的决定,而是多个因素的共同作用</li>
<li>劳动异化简而言之是:站在人的自身发展、自我意志的角度,来看待人与工作的关系。异化程度越高,对人本身的发展越不利。其他方面按下不表,因为前述论点足够进行话题讨论。</li>
</ol>
<p>反思结论如下:</p>
<ol>
<li>劳动异化这个概念,是对资本主义框架的一种解释。在讨论成熟的商业行为时,我们不妨先用该理论作为基础进行分析,当然也可以有其他理论的探讨。</li>
<li>现代性中很重要的一点就是时间和空间的概念与古时不同,城市的出现本就是一个以空间作为明显标志的产物。所以工作空间的固定对劳动者本身的劳动异化是有弱化作用的,这一点对城市内的从业者更加明显。</li>
<li>工作的技能经验在此可以理解为对某一工作本身熟悉度的掌握,对外卖行业而言这一点无从谈起。更加熟悉路况、地形,然后应用到出租车行业?除此之外的积累又有几多?出租车行业本身在其他几点上的情况也极其糟糕,劳动异化程度也不低。</li>
<li>对前述论点举特例无非是五十步笑一百步,劳动异化是多因素的共同作用,而非某一单一因素,恰恰只有外卖行业在前述劳动异化的极端性 (1)(2)(3)(4) 点上均有涉及,且程度不小,所以才可以讨论其职业道德风险的问题。而其他例子总能因某一因素的缺失而削弱其劳动异化程度。比如程序员寡言、风投行业不掌握生产资料,但其获得的回报(物质、心理、社会层面)在一定程度上能够弥补劳动异化带来的损失(物质 & 精神层面)。</li>
<li>「方便无罪」让我想到「技术无罪」论,手机和互联网的出现在社会层面的积极作用当然不用多说,但如果基于功利主义来讨论「外卖是否更利于人与人的交流」的话,笔者认为答案是否定的。而且笔者也不认为「方便」在多大程度上促进了外卖从业者自我人格的发展。倒是在消费者口中助长了工具理性的态度。我们现在反对和反思的不恰恰就是工具理性的消费主义吗?</li>
</ol>
《精通正则表达式》学习笔记(二)
https://acuario.xyz/posts/mastering-regex-summary-2/
2023-09-27T18:25:39+00:00
2019-06-05T21:35:55+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="正则表达式的发展历程">正则表达式的发展历程</h2>
<ul>
<li>
<p>1968 年 Ken Thompson 的文章 Regular Expression Search Algorithm 描述了一种正则表达式编译器,该编译器生成了 IBM7094 的 object 代码。由此也诞生了他的 <code>qed</code>,这种编辑器后来成了 Unix 中 <code>ed</code> 编辑器的基础。</p>
</li>
<li>
<p><code>ed</code> 有条命令 <code>g/Regular Expression/p</code>,读作 <em>Gjobal Regular Expression,Print</em>(应用正则表达式的全局输出)。这个功能最终成为独立的工具 <code>grep</code>,之后又产生了 <code>egrep</code>(Extended grep)。</p>
</li>
<li>
<p>POSIX(Portable Operating System Interface,可移植操作系统接口)诞生于 1986 年,它是一系列标准,确保操作系统之间的移植性。POSIX 把各种常见的流派分为两大类:
Basic Regular Expressions(BREs)和 Extended Regular Expressions(EREs)。POSIX 程序必须支持其中的任意一种。</p>
</li>
</ul>
<p><img src="https://i.loli.net/2019/05/30/5cef9d6eddef290952.png" alt="POSIX 正则表达式流派"></p>
<ul>
<li>
<p>Perl 的特性中值得一提的是,它提供了传统上只有专用工具 <code>sed</code> 和 <code>awk</code> 才提供的正则表达式操作符——这在通用脚本语言中是个首创。正则引擎的代码来自一个早期的项目——Larry 的新闻阅读器 <code>rn</code>(其中的正则表达式代码来自 James Gosling 的 <code>Emacs</code>。(James Gosling 后来去开发他自己的语言 <code>Java</code>,Java 1.4 提供了一个标准的正则表达式包。)</p>
</li>
<li>
<p>1997 年 Philip Hazel 开发了 <code>PCRE</code>,这是一套兼容 Perl 正则表达式的库,全面仿制 Perl 的正则表达式的语法和语义。其他的开发人员可以把 PCRE 整合到自己的工具和语言中,许多流行的软件都使用了 PCRE,例如 <code>PHP</code>、<code>Apache 2</code>、<code>Exim</code>、<code>Postfix</code> 和 <code>Nmap</code>。</p>
</li>
</ul>……
<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="正则表达式的发展历程">正则表达式的发展历程</h2>
<ul>
<li>
<p>1968 年 Ken Thompson 的文章 Regular Expression Search Algorithm 描述了一种正则表达式编译器,该编译器生成了 IBM7094 的 object 代码。由此也诞生了他的 <code>qed</code>,这种编辑器后来成了 Unix 中 <code>ed</code> 编辑器的基础。</p>
</li>
<li>
<p><code>ed</code> 有条命令 <code>g/Regular Expression/p</code>,读作 <em>Gjobal Regular Expression,Print</em>(应用正则表达式的全局输出)。这个功能最终成为独立的工具 <code>grep</code>,之后又产生了 <code>egrep</code>(Extended grep)。</p>
</li>
<li>
<p>POSIX(Portable Operating System Interface,可移植操作系统接口)诞生于 1986 年,它是一系列标准,确保操作系统之间的移植性。POSIX 把各种常见的流派分为两大类:
Basic Regular Expressions(BREs)和 Extended Regular Expressions(EREs)。POSIX 程序必须支持其中的任意一种。</p>
</li>
</ul>
<p><img src="https://i.loli.net/2019/05/30/5cef9d6eddef290952.png" alt="POSIX 正则表达式流派"></p>
<ul>
<li>
<p>Perl 的特性中值得一提的是,它提供了传统上只有专用工具 <code>sed</code> 和 <code>awk</code> 才提供的正则表达式操作符——这在通用脚本语言中是个首创。正则引擎的代码来自一个早期的项目——Larry 的新闻阅读器 <code>rn</code>(其中的正则表达式代码来自 James Gosling 的 <code>Emacs</code>。(James Gosling 后来去开发他自己的语言 <code>Java</code>,Java 1.4 提供了一个标准的正则表达式包。)</p>
</li>
<li>
<p>1997 年 Philip Hazel 开发了 <code>PCRE</code>,这是一套兼容 Perl 正则表达式的库,全面仿制 Perl 的正则表达式的语法和语义。其他的开发人员可以把 PCRE 整合到自己的工具和语言中,许多流行的软件都使用了 PCRE,例如 <code>PHP</code>、<code>Apache 2</code>、<code>Exim</code>、<code>Postfix</code> 和 <code>Nmap</code>。</p>
</li>
</ul>
<h2 id="正则表达式的注意事项和处理方法">正则表达式的注意事项和处理方法</h2>
<p><img src="https://i.loli.net/2019/06/03/5cf503b6304ca16665.png" alt="若干常用工具的 Flavor 的简要考察"></p>
<ul>
<li>
<p>一款工具软件能够利用正则表达式实现的功能,通常比它所属的正则流派更重要。</p>
</li>
<li>
<p>程序设计语言有 3 种处理正则表达式的方式:</p>
<ol>
<li>集成式(integrated):直接内建在语言之中,如 Perl。</li>
<li>程序式(procedural)</li>
<li>面向对象式(object-oriented)</li>
</ol>
<ul>
<li>程序式和面向对象式,是由普通的函数接收普通的字符串,把它们作为正则表达式进行处理。由不同的函数进行不同的、关系到一个或多个正则表达式的操作。</li>
</ul>
</li>
</ul>
<h2 id="字符串字符编码和匹配模式">字符串、字符编码和匹配模式</h2>
<ul>
<li>
<p><code>Unicode</code> 是一组字符设定,或者是从数字和字符之间的逻辑映射的<strong>概念编码</strong>。一个 “代码点(code point)”,通常用十六进制来表示,以 “<code>U+</code>” 开头。</p>
</li>
<li>
<p>支持 Unicode 的程序中的正则表达式通常支持 <code>\unum</code> 元序列,用来匹配一个具体的 Unicode 字符。</p>
</li>
<li>
<p>Unicode Version 3.1 诞生于 2001 年中期,增加了 <code>u+FFFF</code> 之后的代码点。例如,代表音乐谱号 <code>C</code>(Clef)的字符对应代码点 <code>U+1D121</code>。之前那些仅支持低于 <code>U+FPPP</code> 字符的程序无法处理这种情况。大多数程序的 <code>\unum</code> 只能支持最多 4 位十六进制数值。</p>
</li>
<li>
<p>能够处理这类新字符的程序通常提供了 <code>\x{nuwm}</code> 序列,<code>num</code> 可以为任意多位数字(这是为了增强只支持 4 位数字的 <code>\unum</code> 表示法)。你可以使用 <code>\x{1D121}</code> 来匹配这类 “谱号 <code>C</code>” 之类的字符。</p>
</li>
<li>
<p>正则模式和匹配模式</p>
<ul>
<li>不区分大小写的匹配模式:在匹配过程中会忽略字母的大小写。</li>
<li>宽松排列和注释模式:忽略字符组外部的所有空白字符。字符组内部的空白字符仍然有效,<code>#</code> 符号和换行符之间的内容视为注释。</li>
<li>点号通配模式(dot-match-all match mode,也叫 single-line mode “单行模式 "):点号不受限制,可以匹配任何字符,包括换行符。修改了点号处理换行符的方式,从 “需要特殊处理” 变为 “不需要特殊处理”</li>
<li>增强的行锚点模式(Enhanced line-anchor match mode,也叫 “多行文本模式 "):「<code>^</code>」能够匹配字符串中内嵌的文本行的开头位置,「<code>$</code>」能够匹配字符串中内嵌的文本行的换行符。改变了「<code>^</code>」和「<code>$</code>」匹配换行符的方式,从 “不需要特殊处理” 变为 “需要特殊处理”。</li>
<li>文字文本模式:几乎不识别任何正则表达式元字符。</li>
</ul>
</li>
</ul>
<h2 id="常用的元字符和特性">常用的元字符和特性</h2>
<ul>
<li>字符表示法</li>
</ul>
<ul>
<li>字符缩略表示法:<code>\n</code>、<code>\t</code>、<code>\a</code>、<code>\b</code>、<code>\e</code>、<code>\f</code>、<code>\r</code>、<code>\v</code>…</li>
<li>八进制转义:<code>\num</code></li>
<li>十六进制 /Unicode 转义:<code>\xnum</code>、<code>\x{num}</code>、<code>\unum</code>、<code>\Unum</code>…</li>
<li>控制字符:<code>\cchar</code></li>
</ul>
<ul>
<li>字符组及相关结构</li>
</ul>
<ul>
<li>普通字符组:<code>[a-z]</code> 和 <code>[*a-z]</code></li>
<li>几乎能匹配任何字符的元字符:点号</li>
<li>单个字节:<code>\C</code></li>
<li>Unicode 组合字符序列:<code>\X</code></li>
<li>字符组缩略表示法:<code>\w</code>、<code>\d</code>、<code>\s</code>、<code>\W</code>、<code>\D</code>、<code>\S</code></li>
<li>Unicode 属性、区块和分类:<code>\p{Prop}</code>、<code>\P{Prop}</code></li>
<li>字符组运算符:<code>[[a-z]&&[^aeiou]]</code></li>
</ul>
<ul>
<li>
<p>锚点及其他 “零长度断言”</p>
<ul>
<li>行 / 字符串起点:<code>^</code>、<code>\A</code></li>
<li>行 / 字符串终点:<code>$</code>、<code>\Z</code>、<code>\z</code></li>
<li>本次匹配的开始位置(或者上次匹配的结束位置):<code>\G</code></li>
<li>单词分界符:<code>\b</code>、<code>\B</code>、<code>\<</code>、<code>\></code>…</li>
<li>顺序环视 <code>(?=…)</code>、<code>(?!…)</code>;</li>
<li>逆序环视 <code>(?<=…)</code>、<code>(?<!…)</code></li>
</ul>
</li>
<li>
<p>注释和模式修饰词</p>
<ul>
<li>模式修饰词:<code>(?modifier)</code>,例如 <code>(?i)</code> 或 <code>(?-i)</code></li>
<li>模式作用范围:<code>(?modifier:…)</code>,例如 <code>(?i:…)</code></li>
<li>注释:<code>(?#…)</code> 和 <code>#…</code></li>
<li>文字文本范围:<code>\Q…\E</code></li>
</ul>
</li>
<li>
<p>分组,捕获,条件判断和控制:</p>
<ul>
<li>捕获 / 分组括号:<code>(…)</code>、<code>\1</code>、<code>\2</code>,…</li>
<li>仅用于分组的括号:<code>(?:…)</code></li>
<li>命名捕获:<code>(?<Name>…)</code></li>
<li>固化分组:<code>(?>…)</code> 永远也不会 “交还” 分组内已经匹配的任何内容。</li>
<li>多选结构:<code>…|…|…</code></li>
<li>条件判断:<code>(?if then|else)</code></li>
<li>匹配优先量词:<code>*</code>、<code>+</code>、<code>?</code>、<code>{num,num}</code> 贪心(greedy)模式,<strong>默认的</strong>量词匹配模式,匹配尽可能多的内容。</li>
<li>忽略优先量词:<code>*?</code>、<code>+?</code>、<code>??</code>、<code>{num,num)?</code> 懒惰模式,匹配尽可能少的内容,只需要满足下限,匹配就能成功。</li>
<li>占有优先量词:<code>*+</code>、<code>++</code>、<code>?+</code>、<code>{nuwm,nuwm}+</code> 类似固化分组,一旦匹配某些内容,就不会“交还”。</li>
</ul>
</li>
<li>
<p>固化分组就是一个<strong>只进不出</strong>的栈,被匹配入栈的内容不会交还,这导致若匹配了更多无关内容,将导致匹配失败(因为之前的匹配无法交还),最终的匹配结果将为空。例如:<code>!.+!</code> 可以匹配 <code>!Hola!</code>,但 <code>!(?>.+)!</code> 无法匹配 <code>!Hola!</code>。其首先匹配尽可能多的内容 <code>Hola!</code>,但是之后的 <code>!</code> 无法匹配,会强迫 <code>.+</code> 释放之前匹配的 <code>!</code>,但固化分组无法释放,最终导致匹配失败。</p>
</li>
<li>
<p>所有的正则引擎都不会对单词进行语意分析:它们认为 “NE14AD8” 是一个单词,而 “M.I.T.” 不是。</p>
</li>
</ul>
如何加固Linux服务器[译]
https://acuario.xyz/posts/how-to-secure-your-linux-server/
2023-09-27T18:25:39+00:00
2019-04-27T16:54:32+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p><em>原文 <a href="https://medium.com/servers-101/how-to-secure-your-linux-server-6026cfcdefd8">How To Secure Your Linux Server In 7 Easy Steps</a> 由 <a href="https://medium.com/@mutendebrian">Brian Mutende</a> 发布于 Medium,翻译转载已获作者允许。
为配合博客目录系统显示,对原文章节名略有修改。</em></p>
<hr>
<p>大多数服务器经常会被黑客攻击。所以我决定写一篇简短的教程,让读者轻松加固自己的 Linux 服务器。</p>
<p>这并不是一篇完整的安全指南,但是它可以帮你阻断近九成常见的后端攻击,例如<strong>暴力破解</strong>和 <strong>DDoS</strong>。</p>
<p>最棒的是,你可以在一两个小时内就完成操作。</p>
<h2 id="准备工作">准备工作</h2>
<ol>
<li>你需要一台Linux服务器。</li>
<li>你需要对命令行有基本的了解。<a href="https://learncodethehardway.org/unix/bash_cheat_sheet.pdf">这里</a>提供一份 cheet sheet 供你使用。</li>
</ol>
<p>如果你已万事俱备,那就开始吧。</p>……
<p><em>原文 <a href="https://medium.com/servers-101/how-to-secure-your-linux-server-6026cfcdefd8">How To Secure Your Linux Server In 7 Easy Steps</a> 由 <a href="https://medium.com/@mutendebrian">Brian Mutende</a> 发布于 Medium,翻译转载已获作者允许。
为配合博客目录系统显示,对原文章节名略有修改。</em></p>
<hr>
<p>大多数服务器经常会被黑客攻击。所以我决定写一篇简短的教程,让读者轻松加固自己的 Linux 服务器。</p>
<p>这并不是一篇完整的安全指南,但是它可以帮你阻断近九成常见的后端攻击,例如<strong>暴力破解</strong>和 <strong>DDoS</strong>。</p>
<p>最棒的是,你可以在一两个小时内就完成操作。</p>
<h2 id="准备工作">准备工作</h2>
<ol>
<li>你需要一台Linux服务器。</li>
<li>你需要对命令行有基本的了解。<a href="https://learncodethehardway.org/unix/bash_cheat_sheet.pdf">这里</a>提供一份 cheet sheet 供你使用。</li>
</ol>
<p>如果你已万事俱备,那就开始吧。</p>
<h2 id="具体步骤">具体步骤</h2>
<h3 id="配置-ssh-密钥">配置 SSH 密钥</h3>
<p>要访问远程服务器,你务必使用 SSH 密钥登录而不是使用密码登录。</p>
<p>密码登录的问题在于其很容易被暴力破解(你将在下文学到如何进一步防止这种情况)。另外,在每次访问服务器时,你都必须输入密码。为避免上述缺点,你必须设置 <strong>SSH 密钥验证</strong>。它比使用密码更安全,因为黑客无法将其暴力破解。除此以外,使用密钥也可以更方便和快速地连接服务器,而无需输入密码。</p>
<p>下面介绍如何为服务器设置 SSH 身份验证。</p>
<ul>
<li>
<p>在本地计算机上,运行下列命令生成 SSH 密钥对:</p>
<pre tabindex="0"><code>ssh-keygen
</code></pre><p>上述命令将引导你在几步之内生成 SSH 密钥。当然别忘了记住你保存密钥文件的位置。</p>
</li>
<li>
<p>使用以下命令将公钥添加到服务器:</p>
<pre tabindex="0"><code>ssh-copy-id username@remote_host
</code></pre><p>务必使用你的用户名和服务器的 IP 地址替换 <em>username</em> 和 <em>remote_host</em>。系统将提示你输入密码。</p>
</li>
<li>
<p>尝试使用以下命令登录服务器:</p>
<pre tabindex="0"><code>ssh username@remote_host
</code></pre><p>别忘了将 <em>username</em> 和 <em>remote_host</em> 替换为服务器的详细信息。这时你会注意到,本次登录不再提示你输入密码。</p>
</li>
</ul>
<h3 id="保持系统时间最新">保持系统时间最新</h3>
<p>许多安全协议依托于你的系统时间来执行定时任务,生成当天的日志和执行其他关键任务。</p>
<p>如果你的系统时间有误,可能会对你的服务器造成危害。为防止这种情况发生,你可以安装 NTP 客户端。该程序将使你的系统时间与全球 NTP 服务器保持同步。</p>
<p>安装 NTP 客户端命令如下:</p>
<pre tabindex="0"><code>sudo apt install ntp
</code></pre><p>之后你再也不用担心设置系统日期。</p>
<h3 id="查看活动端口">查看活动端口</h3>
<p>服务器程序会暴露某些端口,以便于网络中的其他应用程序对其进行访问。黑客也可以在你的服务器上安装后门并暴露端口,从而控制你的服务器。因此,我们不希望服务器上的未知端口被请求侦听。</p>
<p>要查看活动端口,可以使用以下命令:</p>
<pre tabindex="0"><code>sudo ss -lntup
</code></pre><p>查看输出并检查任何你并不熟悉的端口或进程。尝试发现并追踪可能有害的服务和流程。如果你不知从何下手,请可以查看这份<a href="https://www.garykessler.net/library/bad_ports.html">《「糟糕的」TCP/UDP 端口列表》</a>。</p>
<h3 id="设置防火墙">设置防火墙</h3>
<p>防火墙允许你控制服务器上传入 / 传出特定端口的网络流量。通常我使用 UFW(<em>uncomplicated firewall</em>,简单防火墙)。(译者注:UFW 是 Ubuntu 系统上默认的防火墙组件)</p>
<p>你可以配置下述规则来控制 UFW 的运行:</p>
<ul>
<li>允许 / 禁止</li>
<li>传入流量 / 传出流量</li>
<li>流量目的地 / 流量源</li>
<li>特定端口 / 所有端口</li>
</ul>
<p>完成下面的例子,你将阻止白名单之外的所有网络流量。如果之后安装了其他程序,别忘了将运行所需的必要端口加入白名单。</p>
<h4 id="设置-ufw">设置 UFW</h4>
<ul>
<li>安装ufw。</li>
</ul>
<pre tabindex="0"><code>sudo apt-get install ufw
</code></pre><ul>
<li>你可以禁止所有传出流量</li>
</ul>
<pre tabindex="0"><code>sudo ufw default deny outgoing comment 'deny all outgoing traffic'
</code></pre><ul>
<li>或者允许所有传出流量</li>
</ul>
<pre tabindex="0"><code>sudo ufw default allow outgoing comment 'allow all outgoing traffic'
</code></pre><ul>
<li>接下来,我们要禁止所有传入的流量......</li>
</ul>
<pre tabindex="0"><code>sudo ufw default deny incoming comment 'deny all incoming traffic'
</code></pre><ul>
<li>...将 SSH 连接加入例外,以便访问系统。</li>
</ul>
<pre tabindex="0"><code>sudo ufw limit in ssh comment 'allow SSH connections in'
</code></pre><ul>
<li>如果你将 UFW 配置为禁止所有传出流量,别忘了根据需要允许特定流量。比如:</li>
</ul>
<pre tabindex="0"><code>#允许端口 53 的流量输出 - DNS
sudo ufw allow out 53 comment 'allow DNS calls out'
#允许端口 123 的流量输出 - NTP
sudo ufw allow out 123 comment 'allow NTP out'
#允许 HTTP,HTTPS 或 FTP 的流量
#根据你使用的 apt 源的不同,apt 可能需要如下设置
sudo ufw allow out http comment 'allow HTTP traffic out'
sudo ufw allow out https comment 'allow HTTPS traffic out'
sudo ufw allow out ftp comment 'allow FTP traffic out'
#允许 whois
sudo ufw allow out whois comment 'allow whois'
#允许端口 68 的流量输出 - DHCP 客户端
#如果你正在使用 DHCP,则需要如下设置
sudo ufw allow out 68 comment 'allow the DHCP client to update'
</code></pre><ul>
<li>如需拒绝端口 99 上的任何流量,可使用以下命令:</li>
</ul>
<pre tabindex="0"><code>sudo ufw deny 99
</code></pre><ul>
<li>最后,使用以下命令启动 UFW:</li>
</ul>
<pre tabindex="0"><code>sudo ufw enable
</code></pre><p>你还可以使用以下命令查看 UFW 状态:</p>
<pre tabindex="0"><code>sudo ufw status
</code></pre><h3 id="防止自动化攻击">防止自动化攻击</h3>
<p>你可以使用两个程序来阻止大多数自动化攻击:</p>
<ul>
<li><a href="http://www.cipherdyne.org/psad/">PSAD</a></li>
<li><a href="https://www.fail2ban.org/">Fail2Ban</a></li>
</ul>
<h4 id="psad-和-fail2ban-之间的区别">PSAD 和 Fail2Ban 之间的区别</h4>
<p>我们知道,端口可以提供给服务器上的应用程序进行访问。攻击者为了访问你的服务器,也许会扫描你的服务器目前开放的端口。</p>
<p><strong>PSAD</strong> 监视网络活动,以检测并自定义阻止端口扫描和其他类型的可疑流量,如 DDoS 攻击或操作系统指纹识别尝试。</p>
<p><strong>Fail2Ban</strong> 扫描各种应用程序(如 FTP)的日志文件,并自动封禁有明显恶意行为(如自动登录尝试)的 IP。</p>
<p>以下指南将向你展示如何安装和配置 PSAD 和 Fail2Ban,以便它们与 UFW 一起使用。</p>
<ul>
<li><a href="https://zaiste.net/intro_fail2ban_with_ufw/">安装 Fail2Ban</a></li>
<li><a href="https://gist.github.com/netson/c45b2dc4e835761fbccc">安装 PSAD</a></li>
</ul>
<h3 id="安装-logwatch">安装 logwatch</h3>
<p>服务器上的应用程序通常会将日志消息保存到日志文件中。除非你要手动监控日志文件,否则需要安装 logwatch。logwatch 将扫描系统日志文件并对其进行汇总。</p>
<p>你可以直接从命令行或计划任务运行 logwatch。例如,你可以配置 logwatch 将日志文件的每日摘要以电子邮件的形式发送给你。注意确保你的服务器可以正常发送电子邮件。</p>
<p>logwatch 通过 service 文件来获取读取和汇总日志文件的方式。你可以在 <code>/usr/share/logwatch/scripts/services</code> 中查看所有 service 文件。</p>
<p>logwatch 默认配置文件是 <code>/usr/share/logwatch/default.conf/logwatch.conf</code>。你可以通过使用命令行参数更改配置。</p>
<p>在 Ubuntu 或 Debian 上安装 logwatch,可运行以下命令:</p>
<pre tabindex="0"><code>apt-get install logwatch
</code></pre><p>对于其他 Linux 发行版的用户,请查看 Linode 的<a href="https://www.linode.com/docs/uptime/monitoring/monitor-systems-logwatch/">这篇指南</a>。</p>
<p>如果你需要查看 logwatch 收集的日志样本,你可以尝试直接运行 logwatch。</p>
<pre tabindex="0"><code>sudo /usr/sbin/logwatch --output stdout --format text --range yesterday --service all
</code></pre><p>最后,然后 logwatch 每天发送一封电子邮件,其中包含我们日志文件的摘要。为实现此需求,可以打开文件 <em>/etc/cron.daily/00logwatch</em> 并找到 <em>execute</em> 行,然后将其更改为以下内容:</p>
<pre tabindex="0"><code>/usr/sbin/logwatch --output mail --format html --mailto root --range yesterday --service all
</code></pre><h3 id="执行安全审计">执行安全审计</h3>
<p>在加固 Linux 服务器后,你应该进行安全审计,以便排查任何可能被忽视的安全漏洞。为此,你可以使用 Lynis,这是一个可以实现以下功能的开源软件:</p>
<ul>
<li>安全审计。</li>
<li>一致性测试(例如 PCI,HIPAA,SOx)。</li>
<li>渗透测试。</li>
<li>漏洞检测。</li>
<li>系统强化。</li>
</ul>
<h4 id="如何使用-lynis">如何使用 Lynis</h4>
<p>首先,通过克隆其 Github 仓库来安装 Lynis。这可确保安装的是最新版本的 Lynis。</p>
<pre tabindex="0"><code>git clone https://github.com/CISOfy/lynis
</code></pre><p>切换到我们克隆 Lynis 的目录:</p>
<pre tabindex="0"><code>cd lynis
</code></pre><p>最后,使用以下命令运行第一次安全审计:</p>
<pre tabindex="0"><code>lynis audit system
</code></pre><p>你可以在 Lynis 的<a href="https://cisofy.com/lynis/">官方网站</a>上了解更多相关信息。</p>
<h2 id="结语">结语</h2>
<p>很高兴你能阅读这篇有关加固 Linux 服务器的 how-to 指南。希望你能从中获益。</p>
播客札记(二):996&多才多艺
https://acuario.xyz/others/podcast-note-2/
2023-09-27T18:25:39+00:00
2019-04-25T00:00:00+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="翻电-special-vol04--996-不仅是道德问题">翻电 Special VOL04 | 996 不仅是道德问题</h2>
<p><a href="https://overcast.fm/+GsFgwEus4">Episode Archive</a></p>
<h3 id="996-的现状和成因">996 的现状和成因</h3>
<ul>
<li>超时工作 / 加班最多的工作往往处于社会两端:高收入者(高管、投行)和低收入者(工厂工人、出租车司机、快递员、外卖员)。</li>
<li>高收入者超时工作的原因:由于社会分工程度有上限,具有创造性的工作实际难以再被细节分工。而此类工作大多是无法分工的高产出单人项目。</li>
<li>低收入者超时工作的原因:此类工作是计件工资制度,多劳多得。</li>
<li>正常工作是固定工资模式,其处于高收入者和低收入者之间,涉及的创造性的工作和计件工作不多。</li>
<li>996 运动的爆发来源于高收入者工作模式对正常工作,即固定工资模式的侵入。</li>
<li>互联网行业的军备竞赛导致了对 996 工作制的需求。</li>
<li>不患寡而患不均,996 的出现往往是企业文化的整体问题,而非个别部门的个别现象。</li>
</ul>……
<h2 id="翻电-special-vol04--996-不仅是道德问题">翻电 Special VOL04 | 996 不仅是道德问题</h2>
<p><a href="https://overcast.fm/+GsFgwEus4">Episode Archive</a></p>
<h3 id="996-的现状和成因">996 的现状和成因</h3>
<ul>
<li>超时工作 / 加班最多的工作往往处于社会两端:高收入者(高管、投行)和低收入者(工厂工人、出租车司机、快递员、外卖员)。</li>
<li>高收入者超时工作的原因:由于社会分工程度有上限,具有创造性的工作实际难以再被细节分工。而此类工作大多是无法分工的高产出单人项目。</li>
<li>低收入者超时工作的原因:此类工作是计件工资制度,多劳多得。</li>
<li>正常工作是固定工资模式,其处于高收入者和低收入者之间,涉及的创造性的工作和计件工作不多。</li>
<li>996 运动的爆发来源于高收入者工作模式对正常工作,即固定工资模式的侵入。</li>
<li>互联网行业的军备竞赛导致了对 996 工作制的需求。</li>
<li>不患寡而患不均,996 的出现往往是企业文化的整体问题,而非个别部门的个别现象。</li>
</ul>
<h3 id="商业模式与-996-的关系">商业模式与 996 的关系</h3>
<ul>
<li>普通企业的盈利是基于商品的利润。工作量增多带来的投入产出比相对较低。</li>
<li>互联网行业的盈利是基于股本的增值。估值方法为公司的产品能力、用户数等因素。</li>
<li>劳动与劳动的区分不在于脑体,而在于资本密集程度。资本市场的存在催生互联网行业和投行等领域的高薪 996。</li>
<li>八小时工作制最早由英国空想社会主义者罗伯特・欧文于 1817 年 8 月提出。其后由于欧美资本家对劳工的剥削不断加剧,1886 年 5 月 1 日美国芝加哥爆发了历史最大的罢工,倡导实行八小时工作制。</li>
<li>经济下行期强调、诉求加班文化的企业将会越来越多。在经济下行期,加班将不再只是劳资问题,而将是企业与企业之间军备竞赛的问题。企业主认为在经济下行期控制支出成本的同时提高工作产出,形成企业与企业之间的重商主义。为合理化这一观念,将会出现越来越多提倡奋斗、勤劳文化的论调。</li>
</ul>
<hr>
<h2 id="翻转问答-vol19--应该成为多才多艺的人吗">翻转问答 VOL19 | 应该成为多才多艺的人吗?</h2>
<p><a href="https://overcast.fm/+GsFiolXRY">Episode Archive</a></p>
<h3 id="多样的人生有什么样的假设基础">多样的人生有什么样的假设基础</h3>
<ul>
<li>假设基础:世间的很多禀赋没有高下之分,各种的才能之间都是平等的。</li>
<li>上述假设是多元主义的,同时也具有平民主义的特点。</li>
</ul>
<h3 id="过去的年代人们有什么样的生活重心">过去的年代人们有什么样的生活重心</h3>
<ul>
<li>中世纪社会认为人寻求救赎、追求彼岸最重要,所以僧侣的地位最高。</li>
<li>法国大革命将第一阶级和第三阶级平等化,不因不同社会分工而地位不同。</li>
<li>古希腊没有社会分工,专业化只存在于奴隶中。但依然有依据城邦的存续而发展出来的作为人的第一要务——成为伟大的战士、成为关心城邦政事的自由民。eg.埃斯库罗斯的墓志铭</li>
<li>儒家的承礼启仁是古时的时代精神。</li>
<li>现代社会多才多艺的精英来自于文艺复兴时期的知识分子。</li>
</ul>
<h3 id="今天为何生活失去重心">今天为何生活失去重心</h3>
<ul>
<li>今天的时代失去重心,一切问题没有被化解和体认,而是被掩盖起来,最终导致了现代社会推崇多元精英。</li>
<li>我们不应宣扬没有实指的东西(eg. 优秀、厉害),而应该宣扬找到自己的使命和重心。</li>
</ul>
<h3 id="技术化生活的起点和有效性">技术化生活的起点和有效性</h3>
<ul>
<li>一切多元精英论调的滥觞——《高效人士的 7 个习惯》。</li>
<li>网络上充斥的技术化指导实际难有成效,如:
<ol>
<li><em>有效时间内提高产出</em>;</li>
<li><em>如何面临抉择</em>。</li>
</ol>
</li>
<li>上述技术化指导有效的前提假设是:一个人只要改变想法就可以改变行为,改变行为就可以改变生活。但是改变想法、改变行为和改变生活之间并未有很强的联系。</li>
</ul>
<h3 id="每一个时代都有唯一重要的事">每一个时代都有唯一重要的事</h3>
<ul>
<li>每一个时代都有唯一重要和可欲的事,不代表所有人必须做同样的事。根据人的理解不同,切入点可以不同。</li>
<li>可欲的事非常少,每个人都应以自己的方式体认这个时代的时代精神,并以自己的特殊性和个体性切入行事当中。</li>
</ul>
<h3 id="面向真相敞开">面向真相敞开</h3>
<ul>
<li>如果要接近时代症结,就需要面向真相敞开。由于现代社会语言已经弱化和腐化,从语言的方向接近真相已经比较困难,所以可以尝试回到身体感受,从具有个体性的身体感受开始找回自己的重心,不要被人为的概念和方法影响。</li>
<li>我们不应该要求自己成为一个比别人更优秀和厉害的人,因为在任何领域毫无止境的比较将把人拉入没有赢面的游戏之中。</li>
<li>不仅仅接受哲学道理,而是感悟其人的经历和经历对其道理带来的影响。eg. 维特根斯坦</li>
</ul>
InnoDB 与 MyISAM 的区别
https://acuario.xyz/posts/differences-between-innodb-and-myisam/
2023-09-27T18:25:39+00:00
2019-04-21T17:24:56+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>目前 MySQL 的数据库引擎一般使用 InnoDB 和 MyISAM,但两者存在一些差别。网上零零散散的文章看起来比较麻烦,这里以表格汇总对比二者区别。如有纰漏,还望读者在评论区指正。</p>
<table>
<thead>
<tr>
<th></th>
<th>InnoDB</th>
<th>MyISAM</th>
</tr>
</thead>
<tbody>
<tr>
<td>MySQL 默认引擎</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>事务</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>并发</td>
<td>表级锁 ✅<br />行级锁 ✅,采用 MVCC 来支持高并发,有可能死锁</td>
<td>表级锁 ✅<br />行级锁 ❌</td>
</tr>
<tr>
<td>外键</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>在线热备份</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>COUNT (*)</td>
<td>无 meta-data 缓存,查全表获取</td>
<td>有 meta-data 缓存,直接获取</td>
</tr>
<tr>
<td>崩溃恢复</td>
<td>通过事务日志来恢复数据库</td>
<td>损坏率高,恢复速度慢,不能安全恢复</td>
</tr>
<tr>
<td>其他</td>
<td>默认隔离级别是可重复读(REPEATABLE READ),通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读</td>
<td>设计简单,数据以紧密格式存储</td>
</tr>
<tr>
<td>索引特性</td>
<td>主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。</td>
<td>DELAY_KEY_WRITE 选项:修改后,新索引数据写入内存中的键缓冲区,清理键缓冲区或者关闭表时才写入磁盘。极大提升写入性能,但崩溃时会造成索引损坏</td>
</tr>
<tr>
<td>全文索引</td>
<td>>= MySQL 5.6.4 ✅<br /> < MySQL 5.6.4 ❌</td>
<td>✅<br />支持 BLOB 和 TEXT 的前 500 个字符索引</td>
</tr>
<tr>
<td>自有特性</td>
<td>内部优化:<br />1. 可预测性读加快读操作<br />2. 自适应哈希索引加速插入操作的插入缓冲区</td>
<td>1. 支持压缩表和空间数据索引<br />2.并发插入(CONCURRENT INSERT):在表有读取操作的同时,也可以往表中插入新的记录</td>
</tr>
</tbody>
</table>……
<p>目前 MySQL 的数据库引擎一般使用 InnoDB 和 MyISAM,但两者存在一些差别。网上零零散散的文章看起来比较麻烦,这里以表格汇总对比二者区别。如有纰漏,还望读者在评论区指正。</p>
<table>
<thead>
<tr>
<th></th>
<th>InnoDB</th>
<th>MyISAM</th>
</tr>
</thead>
<tbody>
<tr>
<td>MySQL 默认引擎</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>事务</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>并发</td>
<td>表级锁 ✅<br />行级锁 ✅,采用 MVCC 来支持高并发,有可能死锁</td>
<td>表级锁 ✅<br />行级锁 ❌</td>
</tr>
<tr>
<td>外键</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>在线热备份</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>COUNT (*)</td>
<td>无 meta-data 缓存,查全表获取</td>
<td>有 meta-data 缓存,直接获取</td>
</tr>
<tr>
<td>崩溃恢复</td>
<td>通过事务日志来恢复数据库</td>
<td>损坏率高,恢复速度慢,不能安全恢复</td>
</tr>
<tr>
<td>其他</td>
<td>默认隔离级别是可重复读(REPEATABLE READ),通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读</td>
<td>设计简单,数据以紧密格式存储</td>
</tr>
<tr>
<td>索引特性</td>
<td>主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。</td>
<td>DELAY_KEY_WRITE 选项:修改后,新索引数据写入内存中的键缓冲区,清理键缓冲区或者关闭表时才写入磁盘。极大提升写入性能,但崩溃时会造成索引损坏</td>
</tr>
<tr>
<td>全文索引</td>
<td>>= MySQL 5.6.4 ✅<br /> < MySQL 5.6.4 ❌</td>
<td>✅<br />支持 BLOB 和 TEXT 的前 500 个字符索引</td>
</tr>
<tr>
<td>自有特性</td>
<td>内部优化:<br />1. 可预测性读加快读操作<br />2. 自适应哈希索引加速插入操作的插入缓冲区</td>
<td>1. 支持压缩表和空间数据索引<br />2.并发插入(CONCURRENT INSERT):在表有读取操作的同时,也可以往表中插入新的记录</td>
</tr>
</tbody>
</table>
<hr>
<p>参考链接:
<a href="https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/MySQL.md#%E4%B8%89%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E">技术面试必备基础知识:MySQL</a>
<a href="http://cxymrzero.github.io/blog/2015/08/17/myisam-innodb/">MyISAM 与 InnoDB 区别</a>
<a href="https://juejin.im/post/5b1685bef265da6e5c3c1c34">MySQL 常见的两种存储引擎:MyISAM 与 InnoDB 的爱恨情仇</a></p>
播客札记(一):亲密关系&中医
https://acuario.xyz/others/podcast-note-1/
2023-09-27T18:25:39+00:00
2019-04-12T00:00:00+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="翻转问答-vol8--亲密关系">翻转问答 VOL8 | 亲密关系</h2>
<p><a href="https://overcast.fm/+GsFgR-JZI">Episode Archive</a></p>
<h3 id="亲密关系的特点">亲密关系的特点</h3>
<ul>
<li>个人主义社会——代表排除共同体、排除外部主张的合理性,关注自我的合理性,且自我合理性不与所处共同体相关,是一种纯粹的根本的自我。</li>
<li>亲密关系是一种纯粹关系,与个人主义的自我产生关联,过去的亲密关系属于共同体(家庭、集体),如今属于自我。</li>
<li>现代自我拥有物理和心理意义上更多的私人空间,亲密关系与私人空间的冲突恰是其特殊性。</li>
<li>亲密关系可以充分满足自我认可。因为:
<ol>
<li>亲密关系是自信心和基础安全感的来源;</li>
<li>亲密关系是制度化社会中几乎唯一的非制度要素的情景,用以释放制度压抑(福柯提出性和药物释放制度压抑);</li>
<li>荣格心理学认为,亲密关系是人与自身异性人格(anima 和 animus)达成和解的要素,即是自身自信。</li>
</ol>
</li>
</ul>……
<h2 id="翻转问答-vol8--亲密关系">翻转问答 VOL8 | 亲密关系</h2>
<p><a href="https://overcast.fm/+GsFgR-JZI">Episode Archive</a></p>
<h3 id="亲密关系的特点">亲密关系的特点</h3>
<ul>
<li>个人主义社会——代表排除共同体、排除外部主张的合理性,关注自我的合理性,且自我合理性不与所处共同体相关,是一种纯粹的根本的自我。</li>
<li>亲密关系是一种纯粹关系,与个人主义的自我产生关联,过去的亲密关系属于共同体(家庭、集体),如今属于自我。</li>
<li>现代自我拥有物理和心理意义上更多的私人空间,亲密关系与私人空间的冲突恰是其特殊性。</li>
<li>亲密关系可以充分满足自我认可。因为:
<ol>
<li>亲密关系是自信心和基础安全感的来源;</li>
<li>亲密关系是制度化社会中几乎唯一的非制度要素的情景,用以释放制度压抑(福柯提出性和药物释放制度压抑);</li>
<li>荣格心理学认为,亲密关系是人与自身异性人格(anima 和 animus)达成和解的要素,即是自身自信。</li>
</ol>
</li>
</ul>
<h3 id="亲密关系为何脆弱">亲密关系为何脆弱</h3>
<ul>
<li>现代生活中,维系亲密关系的外部必然性消失,促使人反思自身的亲密关系,但亲密关系本身禁不起反思。</li>
<li>社会流动性越来越大,增加了更多亲密关系的选择。</li>
<li>亲密关系博弈成为囚徒困境博弈,结合亲密关系边际效应使人更愿意考虑成本和收益而做出选择。</li>
<li>开放式关系看似消解了亲密关系的囚徒困境,但依旧无法达成 anima 和 animus 和解,且个人主义的本质下,亲密关系是一对一的。</li>
</ul>
<h3 id="现代知识异化中对亲密关系的-5-种关键隐喻">现代知识异化中对亲密关系的 5 种关键隐喻</h3>
<ol>
<li>健康——感情健康。根本原因是纯粹的亲密关系失去了基础。难免被套用到客观评判体系,引入制度和技术对亲密关系进行调和。</li>
<li>企业——如何「经营」感情。</li>
<li>镜像神经元——充分了解对方、完全换位思考理解对方。</li>
<li>信仰——亲密关系是心诚则灵的东西。信仰在宗教中只照顾生活中与自我存在相关的绝对要素,如救赎——而不是现实功利主义在乎的东西。</li>
<li>自我——爱别人首先要爱自己。这是纯粹个人主义对亲密关系的排除。但除了自恋之外的「爱」本身就是否定自我的过程,要爱自己,不得不承认宾我与主我的存在,并反对接受宾我的反思。能够做到彻底的自爱的人,定是一个绝对自私的人。</li>
</ol>
<h3 id="如何保卫亲密关系">如何保卫亲密关系</h3>
<ol>
<li>不仅保卫亲密关系,也要保卫其他真正的关系——如亲情关系、友情关系。</li>
<li>通过其他真正的关系来锻炼自己承担人际风险的能力,从而减弱自己的胆怯和容易在亲密关系中收到的伤害。</li>
</ol>
<hr>
<h2 id="翻转问答-vol9--如何看待中医和西医的对比">翻转问答 VOL9 | 如何看待中医和西医的对比</h2>
<p><a href="https://overcast.fm/+GsFjiSGOA">Episode Archive</a></p>
<ul>
<li>伪科学是指任何经宣称为科学,或描述方式看起来像科学,但实际上并不符合科学方法基本要求的知识、缺乏支持证据,经不起可信性测试,或缺乏科学形式,伪科学常常使用模糊的、自相矛盾的、夸张的或无法证明的主张,过度依赖确认而不是严格的反驳,缺乏其它专家的公开确认,缺乏系统化、理性化的理论过程。</li>
<li>中医是“伪科学”还是“非科学”?</li>
<li>科学还原论试图将各种领域完全祛魅,进行彻底的科学化。中医是否需要像艺术、宗教一样进行科学化?人的身体和医学一定要“科学化”吗?</li>
</ul>
<h3 id="物理世界是否必须科学化">物理世界是否必须科学化?</h3>
<ul>
<li>物理世界的分类:
<ol>
<li>真实感受建构的世界:食物-味觉,按摩-触觉;</li>
<li>目的建构的世界:与目的高度相关——交通、建筑;</li>
<li>数学建构的世界:完全的抽象世界。</li>
</ol>
</li>
<li>真实感受的物理世界的语汇与科学的语汇存在范式差异:如味觉「鲜」(厨师烹饪时加糖提鲜)实际并非用科学语境下的「鲜味」。所以并非所有场景都要用科学语汇来替代真实感受的物理世界的语汇。</li>
<li>目的的物理世界由于存在理论与实践的差异,但并非所有实践都需要确切的理论认识:如鸟的飞行行为本身并不依赖于理论认识;部分尖端科技的发现(认识)是实践(实验)中的偶然,并非现有认识才有实践。</li>
<li>数学(及其相关)的物理世界由于完全抽象而进行了科学化:如天文学的观测结果、基因层面的理论等。</li>
</ul>
<h3 id="医学是否应该属于数学的物理世界">医学是否应该属于数学的物理世界?</h3>
<ul>
<li>基础假设:科学构筑了现象世界以外的不能被感官感知的现象,这些东西是比被感官感知的东西更本质的原因。即如果能找到非无感现象的原因,则五感现象基本都是偏见和错误。</li>
<li>相信科学即相信上述基础假设。</li>
<li>现代医学的专业化细分使其可以属于数学的物理世界这一范畴。西医对细节化学现象的分析、对人体化学还原的做法是逻辑自洽的。</li>
<li>医学自洽是对细节化学现象的自洽,而非对人整体的自洽。</li>
<li>副作用的存在没有证伪任何化学理论,而是提出了更多难以解释的现象。</li>
</ul>
<h3 id="证伪是什么意思证伪很重要吗">证伪是什么意思?证伪很重要吗?</h3>
<ul>
<li>「证伪 = 求真」是语言误用。</li>
<li>被证伪不代表因果性不存在。</li>
<li>只有科学可以被证伪,但日常医学实践并未以证伪的方式推进科学。</li>
<li>证伪、实证并非最重要的方法论。</li>
</ul>
<h3 id="西医的现状和逻辑问题">西医的现状和逻辑问题</h3>
<ul>
<li>西医治疗的是微观的现象(症状),而非整个人体本身。</li>
<li>人体的健康状况不是细节现象,而整体宏观秩序。</li>
<li>西医的统计学基础决定了受众是社会整体,而非单个个体,西医以社会工程学为基础,而非个体研究为基础。临床检验流程,是从社会工程学角度确定药物对社会的安全性,而非对独立个体的安全性。同时,统计样本的选取,也左右着西医实际参考价值。个体差异的复杂性导致个体参与医学治疗的差异性。</li>
</ul>
<h3 id="中医有没有理论">中医有没有理论?</h3>
<ul>
<li>专家崇拜是现代性的一大问题。以信托的方式相信专家,是存在实际风险和问题的。</li>
<li>中医并非没有理论,而是非科学理论。</li>
<li>中医的理论前提是阴阳五行的信念,西医的理论前提是数学理论的实在。</li>
<li>实用主义角度来看,阴阳五行理论在某种程度上阐释了身体的现象和关系。我们承认其有理,但为何我们否认其「真」?</li>
</ul>
<h3 id="我们需要的一种本体论清醒">我们需要的一种“本体论”清醒</h3>
<ul>
<li>认为科学发展可以一往无前,将有科学宗教和科学迷信的风险。</li>
<li>大多数科学的发现是应用领域的新应用,而非原理领域的新发现。</li>
<li>科学意义的「存在」和我们五感的「存在」并非相同意义,我们虽未以五感方式认知其科学「存在」,但我们对其有信任。这与阴阳五行理论的「存在」并无本质差异。</li>
<li>真理掌握我们,而非我们掌握真理。</li>
</ul>
<h3 id="为何中医话题敏感">为何中医话题敏感?</h3>
<ul>
<li>以公共说理和公共舆论为重要基础,科学的公共话题变得比较敏感。</li>
<li>人被隔绝的日常实践,通过口头表达和表达被人承认获得自我认知和实现。</li>
<li>随着互联网发展,公共言论和公共舆论与权力高度相关。</li>
<li>在公共说理领域,面对多变的环境和不确定性的受众,我们需要一种货币一样的硬通货来说理——普遍主义。</li>
<li>启蒙理性和科学,诞生于对神学的批判,但在批驳的同时继承了神学的确定性和普遍主义。</li>
<li>科学无法争取的普遍主义的领域,将被权力斥为不重要和无意义。如艺术、形而上学、人生价值。</li>
<li>认为「一个领域必须留给其专业的、有其实践经验的人」的想法,是十分傲慢、不负责任、导致社会进一步切割的观念。专家崇拜是现代性涌现的巨大问题,它带来社会盲目和个体自信心和安全感的丧失。</li>
</ul>
SS/SSR中转V2ray起飞教程
https://acuario.xyz/posts/delegate-v2ray-traffic-to-ss-or-ssr/
2023-09-27T18:25:39+00:00
2019-04-01T15:58:18+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>本文目标读者:</p>
<ul>
<li>拥有自建 V2Ray 代理</li>
<li>有机场使用经验</li>
<li>没钱买高价机场 / 乐于使(bái)用(piáo)公益机场</li>
<li>使用机场服务,但忌惮流量安全</li>
</ul>
<h2 id="前言">前言</h2>
<p>目前市面上已经有很多机场(提供 SS/SSR 服务的网站),且不乏众多公益机场,这些机场因为拥有一些好线路的服务器,所以在使用的时候可以获得较好的突破网络封锁的体验。比起自己购买一个垃圾服务器,使用时的龟速;以及购买一个优质线路服务器,承受每月高额费用;更不用说还要担心自己服务器被 GFW 认证的风险——使用机场真是省钱省心。但是隐私问题也不容小觑,支付时的隐私泄露按下不表,本文的初衷是规避使用机场时流量隐私泄露的问题——如何使用机场服务的同时不暴露自己的流量隐私。</p>
<p>V2Ray 除了支持自有协议 VMess 之外,还支持 Socks、Shadowsocks 等协议,配合自带的流量中转功能,可以在保护流量隐私的同时,借助机场起飞,最大程度上提升代理使用体验。</p>
<p>前面说这么多,说人话就是——花最少的钱,用最好的线路,让偷窥流量 / 监控流量的机场见鬼去吧。</p>……
<p>本文目标读者:</p>
<ul>
<li>拥有自建 V2Ray 代理</li>
<li>有机场使用经验</li>
<li>没钱买高价机场 / 乐于使(bái)用(piáo)公益机场</li>
<li>使用机场服务,但忌惮流量安全</li>
</ul>
<h2 id="前言">前言</h2>
<p>目前市面上已经有很多机场(提供 SS/SSR 服务的网站),且不乏众多公益机场,这些机场因为拥有一些好线路的服务器,所以在使用的时候可以获得较好的突破网络封锁的体验。比起自己购买一个垃圾服务器,使用时的龟速;以及购买一个优质线路服务器,承受每月高额费用;更不用说还要担心自己服务器被 GFW 认证的风险——使用机场真是省钱省心。但是隐私问题也不容小觑,支付时的隐私泄露按下不表,本文的初衷是规避使用机场时流量隐私泄露的问题——如何使用机场服务的同时不暴露自己的流量隐私。</p>
<p>V2Ray 除了支持自有协议 VMess 之外,还支持 Socks、Shadowsocks 等协议,配合自带的流量中转功能,可以在保护流量隐私的同时,借助机场起飞,最大程度上提升代理使用体验。</p>
<p>前面说这么多,说人话就是——花最少的钱,用最好的线路,让偷窥流量 / 监控流量的机场见鬼去吧。</p>
<h2 id="基本原理">基本原理</h2>
<p><img src="https://i.loli.net/2019/04/01/5ca1b95248225.png" alt="无标题.png"></p>
<p>基本原理大致如下:</p>
<ol>
<li>V2Ray 客户端先将流量使用 VMess 协议加密</li>
<li>按照不同的加密方法:
SS 中转:V2Ray 客户端再使用 SS 协议加密,把两次加密后的流量发送到机场服务器进行中转
SSR 中转:V2Ray 客户端把 VMess 加密流量发给 SSR 客户端,SSR 客户端再使用 SSR 协议加密,把两次加密后的流量发送到机场服务器进行中转</li>
<li>机场服务器对流量进行 SS/SSR 解密后再把流量(VMess 协议加密流量)发往我们自建的 V2Ray 服务器</li>
<li>V2Ray 服务器正常访问网站</li>
<li>网站返回的数据按上述步骤和处理方式原路返回</li>
</ol>
<p>由于机场服务器收到的是 VMess 协议加密后的流量,加密方法又是我们自定义的,所以机场几无可能掌握我们的真实流量。下面动手实操。</p>
<h2 id="ss-中转-v2ray-流量">SS 中转 V2Ray 流量</h2>
<p>V2Ray 自身支持 Shadowsocks 协议,所以 SS 中转 V2Ray 流量按照官方的<a href="https://toutyrater.github.io/advanced/outboundproxy.html">白话文教程</a>来操作就行了。简单来说就是把配置文件中的 <code>outbounds</code> 部分设置为这样:</p>
<pre tabindex="0"><code>{
"outbounds": [
{
"protocol": "vmess",
"settings": { // 此处根据自己的V2Ray设置修改
"vnext": [
{
"address": "1.1.1.1",
"port": 8888,
"users": [
{
"alterId": 64,
"id": "b12614c5-5ca4-4eba-a215-c61d642116ce"
}
]
}
]
},
"proxySettings": {
"tag": "transit" // 把 V2Ray 流量发给 tag 名为 transit 的代理进行转发
}
},
{
"protocol": "shadowsocks",
"settings": { // 此处填上机场某个 SS 服务器的配置
"servers": [
{
"address": "2.2.2.2",
"method": "aes-256-cfb",
"ota": false,
"password": "password",
"port": 1024
}
]
},
"tag": "transit"
}
]
</code></pre><h2 id="ssr-中转-v2ray-流量">SSR 中转 V2Ray 流量</h2>
<p>但是很多机场都是 SSR 机场,没有提供 SS 配置,那岂不是就不能用上面的骚操作了?既然 SSR 支持监听本地的 Socks 流量,V2Ray 又支持 Socks 协议传出,那我们只需要在本地同时打开 V2Ray 和 SSR 客户端,然后用 Socks 协议连接二者通信即可,相当于把上一节中 V2Ray 传出目标从服务器改为本地 SSR。那么配置文件中的 <code>outbounds</code> 部分就设置为这样:</p>
<pre tabindex="0"><code>{
"outbounds": [
{
"protocol": "vmess",
"settings": { // 此处根据自己的V2Ray设置修改
"vnext": [
{
"address": "1.1.1.1",
"port": 8888,
"users": [
{
"alterId": 64,
"id": "b12614c5-5ca4-4eba-a215-c61d642116ce"
}
]
}
]
},
"proxySettings": {
"tag": "transit" // 把 V2Ray 流量发给 tag 名为 transit 的代理进行转发
}
},
{
"protocol": "socks",
"settings": {
"servers": [
{
"address": "127.0.0.1",
"port": 1080 // 此处填写 SSR 客户端监听的本地端口
}
]
},
"tag": "transit"
}
]
</code></pre><p>以 Windows 平台为例,我们可以在客户端的「选项设置」中「允许来自局域网的连接」,并且设置 SSR 客户端监听的本地端口:</p>
<p><img src="https://i.loli.net/2019/04/01/5ca1b95b997fe.png" alt="SSR设置"></p>
<p>完成设置后,在 SSR 客户端中选择想要使用的服务器节点,并且打开 V2Ray,需要代理的流量全部访问 <strong>V2Ray 客户端监听的端口</strong>即可。</p>
<p><img src="https://i.loli.net/2019/04/01/5ca1b95d2597b.png" alt="选择SSR服务器节点"></p>
<p>如果设置正确,访问不存在的网站时,可以在 V2Ray 服务端日志中看到流量全部来自于我们选择机场服务器节点。</p>
<p><img src="https://i.loli.net/2019/04/01/5ca1b95e30487.png" alt="V2Ray服务端日志"></p>
<h2 id="其他">其他</h2>
<h3 id="v2ray-配置文件">V2Ray 配置文件</h3>
<p>刚开始使用 V2Ray 的人可能会困惑于 V2Ray 配置文件的繁琐,下面提供几个与本文相关的,本人目前正在使用的 V2Ray 完整配置文件,其中客户端配置文件集成了基本的广告屏蔽和大陆直连,本地监听端口为 <code>1082</code>,可根据自己需要进行修改。同时也提供了最简单的服务端配置文件,仅供参考:</p>
<ul>
<li><a href="https://gist.github.com/yhyy135/667251599e3e762ca6d86517d39554c8/raw/ba48ac317c5b658b55b4834516d897a4a201a473/ss-vmess-config.json">SS 中转 V2Ray 客户端配置文件</a></li>
<li><a href="https://gist.github.com/yhyy135/667251599e3e762ca6d86517d39554c8/raw/ba48ac317c5b658b55b4834516d897a4a201a473/ssr-vmess-config.json">SSR 中转 V2Ray 客户端配置文件</a></li>
<li><a href="https://gist.github.com/yhyy135/667251599e3e762ca6d86517d39554c8/raw/ba48ac317c5b658b55b4834516d897a4a201a473/server-config.json">V2Ray 服务端配置文件</a></li>
</ul>
<p>另外,由于 SSR 中转 V2Ray 流量需要同时使用 SSR 客户端和 V2Ray 客户端,所以目前暂时无法在移动设备上实现,略有遗憾。但是既然都可以如此白嫖机场了,还是知足吧。如果你有什么好想法,不妨在评论区交流。</p>
使用HyperApp搭建Tiny Tiny RSS
https://acuario.xyz/posts/set-up-tiny-tiny-rss-with-hyperapp/
2023-09-27T18:25:39+00:00
2019-02-26T15:22:31+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="准备">准备</h2>
<ul>
<li>VPS 需要先安装好 <code>docker-ce</code></li>
<li><a href="https://itunes.apple.com/app/apple-store/id1179750280?pt=118260435&ct=guide&mt=8">HyperApp</a></li>
<li>一个已经解析正确的域名(ping 验证)</li>
<li>耐心。仔细。认真</li>
</ul>
<h2 id="hyperapp-服务端配置">HyperApp 服务端配置</h2>
<h3 id="安装-postgresql">安装 PostgreSQL</h3>
<p>虽然 HyperApp 提供了相应的 PostgreSQL 应用一键安装,但是由于安装 Tiny Tiny RSS 时无法与其衔接,所以一并使用 <code>Docker Image</code> 方法进行安装。</p>……
<h2 id="准备">准备</h2>
<ul>
<li>VPS 需要先安装好 <code>docker-ce</code></li>
<li><a href="https://itunes.apple.com/app/apple-store/id1179750280?pt=118260435&ct=guide&mt=8">HyperApp</a></li>
<li>一个已经解析正确的域名(ping 验证)</li>
<li>耐心。仔细。认真</li>
</ul>
<h2 id="hyperapp-服务端配置">HyperApp 服务端配置</h2>
<h3 id="安装-postgresql">安装 PostgreSQL</h3>
<p>虽然 HyperApp 提供了相应的 PostgreSQL 应用一键安装,但是由于安装 Tiny Tiny RSS 时无法与其衔接,所以一并使用 <code>Docker Image</code> 方法进行安装。</p>
<ol>
<li>转到商店页面。找到 <code>Docker Image</code> 然后选择服务器并且保存进入配置界面</li>
<li>请完全按照下图配置进行填写!</li>
</ol>
<table>
<thead>
<tr>
<th>应用设置名称</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>Image</td>
<td>sameersbn/postgresql:latest</td>
</tr>
<tr>
<td>Options</td>
<td><code>--restart=always -v /srv/docker/postgres/data/:/var/lib/postgresql/ -e PG_PASSWORD=mydbpass -e DB_EXTENSION=pg_trgm -p 5432:5432</code></td>
</tr>
<tr>
<td>Command</td>
<td></td>
</tr>
<tr>
<td>Args</td>
<td></td>
</tr>
<tr>
<td>其他</td>
<td>所有其他设置均为空</td>
</tr>
</tbody>
</table>
<h3 id="安装-tiny-tiny-rss">安装 Tiny Tiny RSS</h3>
<ol>
<li>转到商店页面。找到 <code>Docker Image</code> 然后选择服务器并且保存进入配置界面</li>
<li>请完全按照下图配置进行填写!</li>
</ol>
<table>
<thead>
<tr>
<th>应用设置名称</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>Image</td>
<td>wangqiru/ttrss</td>
</tr>
<tr>
<td>Options</td>
<td><code>--restart=always -e SELF_URL_PATH=https://你要给镜像站点的域名 -e DB_HOST=postgres -e DB_PORT=5432 -e DB_NAME=myttrss -e DB_USER=postgres -e DB_PASS=mydbpass</code></td>
</tr>
<tr>
<td>Command</td>
<td></td>
</tr>
<tr>
<td>Args</td>
<td></td>
</tr>
<tr>
<td>Nginx 设置名称</td>
<td>内容</td>
</tr>
<tr>
<td>域名</td>
<td>你要给镜像站点的域名</td>
</tr>
<tr>
<td>应用端口</td>
<td></td>
</tr>
<tr>
<td>Https</td>
<td>不重定向 HTTP 请求</td>
</tr>
<tr>
<td>域名</td>
<td>你要给镜像站点的域名(自动填写)</td>
</tr>
<tr>
<td>邮箱</td>
<td>域名所对应的邮箱</td>
</tr>
</tbody>
</table>
<ul>
<li>保存并且进行安装。请确保这时候 <code>Nginx Proxy</code> 以及 <code>Nginx SSL Support</code> 正常默认安装并且启动了</li>
</ul>
<h3 id="连接数据库">连接数据库</h3>
<p>安装 PostgreSQL 和 Tiny Tiny RSS 后还不能正常使用,还需要将两者连接起来。进入 VPS 的 SSH 窗口执行命令:</p>
<pre tabindex="0"><code>docker network create ttrss_network
docker container ls | grep wangqiru/ttrss | awk '{print $1}' | xargs docker network connect ttrss_network
docker container ls | grep sameersbn/postgresql | awk '{print $1}' | xargs docker network connect ttrss_network
docker container ls | grep wangqiru/ttrss | awk '{print $1}' | xargs docker restart
</code></pre><p>上述命令建立了一个名为 <code>ttrss_network</code> 的 docker 通讯网络,并将 <code>ttrss</code> 容器和 <code>postgres</code> 容器都连接到这个网络内部。最后重启 Tiny Tiny RSS 容器。</p>
<h3 id="防火墙设置">防火墙设置</h3>
<ul>
<li>CentOS</li>
</ul>
<pre tabindex="0"><code>firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --add-port=443/tcp --permanent
firewall-cmd --reload
</code></pre><ul>
<li>Ubuntu</li>
</ul>
<pre tabindex="0"><code>sudo ufw allow 80
sudo ufw allow 443
</code></pre><h2 id="配置使用-tiny-tiny-rss">配置使用 Tiny Tiny RSS</h2>
<h3 id="登录使用">登录使用</h3>
<p><img src="https://i.loli.net/2019/02/26/5c74e8c180d1d.png" alt="Tiny Tiny RSS"></p>
<p>安装完成后,访问你给镜像站点设置的域名即可进入 Tiny Tiny RSS 登陆页面。默认账号是 <code>admin</code>,密码是 <code>password</code>。登录后务必修改密码。Tiny Tiny RSS 的其他设置技巧,可以参阅少数派的<a href="https://sspai.com/post/41302">这篇文章</a>。</p>
<h3 id="全文输出">全文输出</h3>
<p>一些网站并未提供完整的全文 RSS 源,而只提供了文章的摘要内容,阅读起来十分不便。作为 RSS 的重度用户,跳转到网站进行阅读实在是浪费时间。遇到这样的 RSS 源,除了可以使用内置了 Mercury 全文输出功能的客户端(iOS 平台 Reeder、Unread 等主流 RSS 阅读器支持)以外,还可以为自己搭建的 Tiny Tiny RSS 安装插件以支持 Mercury 功能。<br>
下面还是使用 HyperApp 来操作,一步到位。</p>
<h4 id="安装-mercury">安装 Mercury</h4>
<ol>
<li>转到商店页面。找到 <code>Docker Image</code> 然后选择服务器并且保存进入配置界面</li>
<li>请完全按照下图配置进行填写!</li>
</ol>
<table>
<thead>
<tr>
<th>应用设置名称</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>Image</td>
<td>wangqiru/mercury-parser-api</td>
</tr>
<tr>
<td>Options</td>
<td><code>-p 3000:3000</code></td>
</tr>
<tr>
<td>Command</td>
<td></td>
</tr>
<tr>
<td>Args</td>
<td></td>
</tr>
<tr>
<td>其他</td>
<td>所有其他设置均为空</td>
</tr>
</tbody>
</table>
<h4 id="防火墙设置-1">防火墙设置</h4>
<ul>
<li>CentOS</li>
</ul>
<pre tabindex="0"><code>firewall-cmd --add-port=3000/tcp --permanent
firewall-cmd --reload
</code></pre><ul>
<li>Ubuntu</li>
</ul>
<pre tabindex="0"><code>sudo ufw allow 3000
</code></pre><h4 id="配置-mercury-插件">配置 Mercury 插件</h4>
<ol>
<li>登陆 Tiny Tiny RSS,进入偏好设置(Preferences) - 插件(Plugins),启用 mercury_fulltext 的插件</li>
<li>登陆 Tiny Tiny RSS,进入偏好设置(Preferences) - 信息源(Feeds) - Mercury_fulltext settings (mercury_fulltext) 选项卡。填入 <code>http://你要给镜像站点的域名或IP地址:3000</code> ,保存配置</li>
</ol>
<h4 id="开始使用-mercury">开始使用 Mercury</h4>
<ol>
<li>首先正常订阅一个 RSS 源</li>
<li>在首页左侧导航或订阅源管理中找到需要获取全文的订阅源,点击编辑订阅源(Edit Feed)</li>
<li>进入编辑订阅源(Edit Feed)窗口中的插件(Plugins)选项卡,勾选 <code>Get fulltext via Mercury Parser</code></li>
</ol>
<p>设置完成后,Tiny Tiny RSS 将根据你的自定义设定,对特殊 RSS 源使用 Mercury 拉取全文内容后再生成 RSS 内容。这样可以摆脱客户端的限制,在任何客户端上都能直接浏览全文 RSS 的文章。</p>
<h2 id="qa">Q&A</h2>
<ol>
<li>
<p>为何连接数据库的命令这么长?
之所以命令这么长是因为在使用 HyperApp 安装 <code>ttrss</code> 容器和 <code>postgres</code> 容器时没有为其指定容器的 name,所以必须通过查找其容器 ID 后再进行绑定。</p>
</li>
<li>
<p>为什么安装时不指定容器的 name?
指定容器的 name 可以方便连接数据库,但由于 HyperApp 是通过一定规则生成容器 name 从而对已安装的应用进行管理的,如果自定义了容器的 name,HyperApp 将无法正常识别到容器,安装应用后也会显示尚未安装。</p>
</li>
</ol>
<hr>
<p>参考链接:
<a href="https://github.com/HenryQW/docker-ttrss-plugins">Tiny Tiny RSS 容器镜像</a>
<a href="https://henry.wang/2018/04/25/ttrss-docker-plugins-guide.html">A ttrss setup guide - Start your own RSS aggregator today</a>
<a href="https://sspai.com/post/41302">如何搭建属于自己的 RSS 服务,高效精准获取信息</a>
<a href="https://www.hyperapp.fun/zh/advanced/docker-image-introduction.html">Docker-image 介绍</a>
<a href="https://www.hyperapp.fun/zh/mirror.html">超简单搭建常见 404 站点镜像</a></p>
非常简单的Python3 HTTP服务
https://acuario.xyz/posts/create-simple-http-server-with-python3/
2023-09-27T18:25:39+00:00
2019-02-26T14:35:09+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>多年前在<a href="http://weibo.com/haoel?s=6cm7D0" title="左耳朵耗子">左耳朵耗子</a>的博客上看到<a href="https://coolshell.cn/articles/1480.html">《非常简单的 PYTHON HTTP 服务》</a>一文,在急需建立 HTTP Server 的场合十分有用,比如临时分享文件之类。在 HTTP Server 访问的根目录下只需执行一行命令就能搞定:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python -m SimpleHTTPServer
</span></span></code></pre></td></tr></table>
</div>
</div><p>但是随着 Python 2 逐渐被 Python 3 取代,上述命令无法继续使用。</p>……
<p>多年前在<a href="http://weibo.com/haoel?s=6cm7D0" title="左耳朵耗子">左耳朵耗子</a>的博客上看到<a href="https://coolshell.cn/articles/1480.html">《非常简单的 PYTHON HTTP 服务》</a>一文,在急需建立 HTTP Server 的场合十分有用,比如临时分享文件之类。在 HTTP Server 访问的根目录下只需执行一行命令就能搞定:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python -m SimpleHTTPServer
</span></span></code></pre></td></tr></table>
</div>
</div><p>但是随着 Python 2 逐渐被 Python 3 取代,上述命令无法继续使用。</p>
<p>在 Python3 中没有 <code>SimpleHTTPServer</code>,而是直接使用<code>http.server</code> 即可。所以对应的 Python 3 命令是:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python3 -m http.server
</span></span></code></pre></td></tr></table>
</div>
</div><p>默认开启的 HTTP Server 服务监听的是 8000 端口,使用时注意系统防火墙是否放行。如需使用其他端口,只需在命令末尾加上端口号即可,如使用端口 1234:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python3 -m http.server <span class="m">1234</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="后台运行">后台运行</h2>
<p>上述 Python 运行的 HTTP 服务器必须前台运行命令,并实时输出 log,断开终端后自动停止服务。这时可以借助 <code>nohup</code> 命令使其后台运行:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ nohup python3 -m http.server >>/dev/null <span class="p">&</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>当然你也可以使用其他方法如 <code>screen</code> 等工具实现后台运行,再此就不赘述了。不过既然有更复杂的需要,那还是老老实实用 Nginx 吧。</p>
Linux各种包管理换国内源
https://acuario.xyz/posts/replace-package-source-to-china-mirror/
2023-09-27T18:25:39+00:00
2019-01-18T21:48:40+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>在国外的机器上开发倒是没什么麻烦事,也不用操心这么多。但是由于众所周知的原因,在天朝可就麻烦多了,不想点法子的话下载依赖就够摸鱼一下午了。这么多包管理,不碰不要紧,一碰要狗命(单押x1 XD
干脆把手头用的这几个记一下,免得以后查来查去麻烦。</p>
<h2 id="一键换源脚本">一键换源脚本</h2>
<p>写完 yum 和 apt 的部分才想起来,这种常见的东西应该是有脚本可以搞定的吧。找了下果然有<a href="https://www.oldking.net/697.html">大佬</a>写好了的。
如果只是 Linux 软件包的话就用一个脚本搞定:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ wget -qO- git.io/superupdate.sh <span class="p">|</span> bash
</span></span></code></pre></td></tr></table>
</div>
</div><p>其他包管理的换源反正也不复杂,就手动弄一下。</p>……
<p>在国外的机器上开发倒是没什么麻烦事,也不用操心这么多。但是由于众所周知的原因,在天朝可就麻烦多了,不想点法子的话下载依赖就够摸鱼一下午了。这么多包管理,不碰不要紧,一碰要狗命(单押x1 XD
干脆把手头用的这几个记一下,免得以后查来查去麻烦。</p>
<h2 id="一键换源脚本">一键换源脚本</h2>
<p>写完 yum 和 apt 的部分才想起来,这种常见的东西应该是有脚本可以搞定的吧。找了下果然有<a href="https://www.oldking.net/697.html">大佬</a>写好了的。
如果只是 Linux 软件包的话就用一个脚本搞定:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ wget -qO- git.io/superupdate.sh <span class="p">|</span> bash
</span></span></code></pre></td></tr></table>
</div>
</div><p>其他包管理的换源反正也不复杂,就手动弄一下。</p>
<hr>
<h2 id="yum">YUM</h2>
<p>使用 <a href="https://opsx.alibaba.com/mirror">阿里镜像</a> 作镜像源</p>
<ol>
<li>备份原配置文件 <code>$ mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup</code></li>
<li>换源(注意 OS Version)
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># CentOS 6</span>
</span></span><span class="line"><span class="cl"><span class="c1"># wget 方式获取</span>
</span></span><span class="line"><span class="cl">$ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
</span></span><span class="line"><span class="cl"><span class="c1"># curl 方式获取</span>
</span></span><span class="line"><span class="cl">$ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># CentOS 7</span>
</span></span><span class="line"><span class="cl"><span class="c1"># wget 方式获取</span>
</span></span><span class="line"><span class="cl">$ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
</span></span><span class="line"><span class="cl"><span class="c1"># curl 方式获取</span>
</span></span><span class="line"><span class="cl">$ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>刷新 cache 生效 <code>$ yum makecache</code></li>
</ol>
<h2 id="apt">APT</h2>
<p>使用 <a href="https://opsx.alibaba.com/mirror">阿里镜像</a> 作镜像源</p>
<ol>
<li>备份原配置文件 <code>$ cp /etc/apt/sources.list /etc/apt/sources.list_backup</code></li>
<li>清空配置 <code>$ echo "" > /etc/apt/sources.list</code></li>
<li>换源(注意按 OS Version 进行添加) <code>$ vim /etc/apt/sources.list</code>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Ubuntu 14.04.5 LTS</span>
</span></span><span class="line"><span class="cl">deb https://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src https://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb https://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src https://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb https://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src https://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb https://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src https://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ubuntu 16.04</span>
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ xenial main
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ xenial main
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ xenial universe
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ xenial universe
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ xenial-security main
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security universe
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ubuntu 18.04(bionic)</span>
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Debian 7.x (wheezy)</span>
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ wheezy main non-free contrib
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ wheezy-proposed-updates main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ wheezy main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ wheezy-proposed-updates main non-free contrib
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Debian 8.x (jessie)</span>
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ jessie main non-free contrib
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ jessie-proposed-updates main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ jessie main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ jessie-proposed-updates main non-free contrib
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Debian 9.x (stretch)</span>
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ stretch main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ stretch main non-free contrib
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian-security stretch/updates main
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian-security stretch/updates main
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ol>
<h2 id="pippip3">pip/pip3</h2>
<h3 id="永久换源">永久换源</h3>
<p>使用 <a href="https://opsx.alibaba.com/mirror">阿里镜像</a> 作镜像源
在配置文件中添加配置项 <code>vim ~/.pip/pip.conf</code></p>
<pre tabindex="0"><code>[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host=mirrors.aliyun.com
</code></pre><h3 id="临时换源">临时换源</h3>
<p>在使用 pip/pip3 命令安装软件时,在命令中添加参数 <code>-i https://mirrors.aliyun.com/pypi/simple/</code>
例如升级 pip 的命令为:<code>pip install -U pip -i https://mirrors.aliyun.com/pypi/simple/</code></p>
<h2 id="docker">Docker</h2>
<p>使用 <a href="http://www.docker-cn.com/registry-mirror">Docker 中国</a> 作镜像源
一般情况下修改配置文件<code>$ vim /etc/docker/daemon.json</code></p>
<p>添加下面配置项:</p>
<pre tabindex="0"><code>{
"registry-mirrors": ["https://registry.docker-cn.com/"]
}
</code></pre><p>然后重启 docker deamon 即可</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ systemctl daemon-reload
</span></span><span class="line"><span class="cl">$ systemctl restart docker
</span></span></code></pre></td></tr></table>
</div>
</div><p>如果是通过 snappy(Ubuntu 16.04+)安装的 docker 的话,配置文件路径和重启命令都不同,配置内容一样:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ vim /var/snap/docker/current/config/daemon.json
</span></span><span class="line"><span class="cl">$ snap restart docker
</span></span></code></pre></td></tr></table>
</div>
</div><p>运行命令<code>$ docker info</code>,查看其中的配置项是否正确:</p>
<pre tabindex="0"><code>Registry Mirrors:
https://registry.docker-cn.com/
</code></pre><p><a href="https://lug.ustc.edu.cn/wiki/mirrors/help/docker">Docker 镜像使用帮助 [LUG@USTC]</a></p>
<h2 id="composer">Composer</h2>
<p>使用 <a href="https://pkg.phpcomposer.com/">Packagist</a> 作镜像源</p>
<h3 id="全局配置">全局配置</h3>
<p>任意目录下执行下例命令即可:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ composer config -g repo.packagist composer https://packagist.phpcomposer.com
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="单个项目配置">单个项目配置</h3>
<p>进入项目目录 <code>dir</code> 执行命令:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ composer config repo.packagist composer https://packagist.phpcomposer.com
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="npm">NPM</h2>
<p>使用 <a href="https://npm.taobao.org/">淘宝 NPM 镜像</a> 作镜像源
使用淘宝 NPM 定制的 <a href="https://github.com/cnpm/cnpm">cnpm</a> (gzip 压缩支持) 命令行工具代替默认的 <code>npm</code>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ npm install -g cnpm --registry<span class="o">=</span>https://registry.npm.taobao.org
</span></span></code></pre></td></tr></table>
</div>
</div><p>或者通过添加 <code>npm</code> 参数 <code>alias</code> 一个新命令:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ <span class="nb">alias</span> <span class="nv">cnpm</span><span class="o">=</span><span class="s2">"npm --registry=https://registry.npm.taobao.org \
</span></span></span><span class="line"><span class="cl"><span class="s2">--cache=</span><span class="nv">$HOME</span><span class="s2">/.npm/.cache/cnpm \
</span></span></span><span class="line"><span class="cl"><span class="s2">--disturl=https://npm.taobao.org/dist \
</span></span></span><span class="line"><span class="cl"><span class="s2">--userconfig=</span><span class="nv">$HOME</span><span class="s2">/.cnpmrc"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## Or alias it in .bashrc or .zshrc</span>
</span></span><span class="line"><span class="cl">$ <span class="nb">echo</span> <span class="s1">'\n#alias for cnpm\nalias cnpm="npm --registry=https://registry.npm.taobao.org \
</span></span></span><span class="line"><span class="cl"><span class="s1"> --cache=$HOME/.npm/.cache/cnpm \
</span></span></span><span class="line"><span class="cl"><span class="s1"> --disturl=https://npm.taobao.org/dist \
</span></span></span><span class="line"><span class="cl"><span class="s1"> --userconfig=$HOME/.cnpmrc"'</span> >> ~/.zshrc <span class="o">&&</span> <span class="nb">source</span> ~/.zshrc
</span></span></code></pre></td></tr></table>
</div>
</div>
如何优雅地找资源
https://acuario.xyz/posts/how-to-get-source/
2023-09-27T18:25:39+00:00
2018-11-10T01:16:52+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li>2019.10.7 更新,删除失效网站,补充流播视频网站推荐</li>
</ul>
<p><img src="https://i.loli.net/2018/11/10/5be5c84f8f10e.jpg" alt=""></p>
<p>其实在网络上需要查找一些什么资源并不像我们想象的那样难。如果学会利用搜索引擎,再加上几个好用的、值得信赖的网站,基本上可以事半功倍。所以对于普通人来说,做一个「资源帝」其实只是需要一个手册和方法论的指导而已。
著名的资源帝<a href="http://shedingkong.lofter.com/tag/%E7%BD%91%E7%AB%99%E6%8E%A8%E8%8D%90">设定控</a>提供的各类手册当然十分完美,但是我们实际用不到如此多的网站。除非你是松鼠症患者,有收集整理的心理刚需,否则资源手册的噪音大过实际效益。</p>
<p>这篇水分满满的文章也仅仅只是梳理一下笔者的资源搜索路径,按照几个主要的资源类型进行展开,顺便配上一些评(fei)论(hua),以供各位参考,基本上能搞定 80% 的书、影、音需求。</p>
<p>p.s. 关于文中的软件推荐,均以 Windows 为平台,暂未收录 macOS 相关软件。</p>……
<ul>
<li>2019.10.7 更新,删除失效网站,补充流播视频网站推荐</li>
</ul>
<p><img src="https://i.loli.net/2018/11/10/5be5c84f8f10e.jpg" alt=""></p>
<p>其实在网络上需要查找一些什么资源并不像我们想象的那样难。如果学会利用搜索引擎,再加上几个好用的、值得信赖的网站,基本上可以事半功倍。所以对于普通人来说,做一个「资源帝」其实只是需要一个手册和方法论的指导而已。
著名的资源帝<a href="http://shedingkong.lofter.com/tag/%E7%BD%91%E7%AB%99%E6%8E%A8%E8%8D%90">设定控</a>提供的各类手册当然十分完美,但是我们实际用不到如此多的网站。除非你是松鼠症患者,有收集整理的心理刚需,否则资源手册的噪音大过实际效益。</p>
<p>这篇水分满满的文章也仅仅只是梳理一下笔者的资源搜索路径,按照几个主要的资源类型进行展开,顺便配上一些评(fei)论(hua),以供各位参考,基本上能搞定 80% 的书、影、音需求。</p>
<p>p.s. 关于文中的软件推荐,均以 Windows 为平台,暂未收录 macOS 相关软件。</p>
<h2 id="电子书">电子书</h2>
<h3 id="网站">网站</h3>
<ul>
<li>
<p><a href="https://www.mlook.mobi/">mLook</a><br>
mLook 可以应付绝大多数的电子书需求,但是<strong>已经关闭开放注册</strong>。</p>
</li>
<li>
<p><a href="https://book.51read.site/">Kindle电子书分享网</a><br>
最近找到的一个比较不错的电子书搜索引擎。</p>
</li>
<li>
<p><a href="https://forum.readfree.me/">readfree</a><br>
readfree 是我在众多书签中发掘到的质量上乘的付费下载网站,充值 10¥可以下载 1k 次,或者靠自己上传书籍的下载量来获取下载次数。我搜了几本书都有资源,当作备用网站不妨一试。</p>
</li>
<li>
<p><a href="https://www.easysearch.com.tw/">EasySearch</a><br>
EasySearch 是<a href="https://www.ymdie.com/archives/32219">港台电子书</a>的搜索引擎,支持搜索博客來、<a href="https://www.kobo.com/tw/zh">乐天 Kobo</a>、<a href="https://readmoo.com/">读墨 Readmoo</a>、Taaze、Google Play 的电子书商品信息,你可以在上述网站购买电子书,使用各平台的客户端进行阅读。如果你想在 Kindle 上阅读 Kobo 商城购买的电子书,你可以按照<a href="https://twitter.com/yhyy135/status/1028389615730917376">这个教程</a>进行操作。</p>
</li>
<li>
<p>Telegram 频道<br>
如果你使用 <a href="https://telegram.org/">Telegram</a> 的话(已被封锁),这里提供几个分享电子书的 Telegram 频道:<br>
<a href="https://t.me/zebookpush">kindle电子书读书会</a>:频道每天据群友请求推书。只推原版无损高质 kindle 电子书。需要书时,直接前往<a href="https://t.me/zebook">Telegram 群组</a>求书即可。<br>
<a href="https://t.me/booksforeverybody">书籍分享</a><br>
<a href="https://t.me/free_programming_books">电子书支援计划_技术分享</a>:分享技术类书籍为主</p>
</li>
</ul>
<h3 id="软件">软件</h3>
<ul>
<li>
<p><a href="https://calibre-ebook.com/">Calibre</a><br>
Calibre 是使用 Kindle 的人必备的软件,可以把 mobi、epub、awz3、txt、pdf 等各种格式的电子书进行转换。</p>
</li>
<li>
<p><a href="https://www.sumatrapdfreader.org/free-pdf-reader.html">SumatraPDF</a><br>
SumatraPDF 是我在 Windows 上主要使用的电子阅读器,软件体积很小,而且可以打开 mobi、epub、azw3,满足了我日常所需。使用时,建议将<code>菜单 - 设置 - 高级选项</code>内的 <code>EbookUI - UseFixedPageUI</code> 值设为 <code>true</code>,否则无法在阅读时选中文本。</p>
</li>
</ul>
<h2 id="音乐">音乐</h2>
<p>好像已经毫无疑问地迈入流媒体时代了,很久没有再下载过 mp3 文件,然后耐心维护本地曲库了。除非实在喜欢的音乐不妨下载一份在本地备用。</p>
<h3 id="网站-1">网站</h3>
<ul>
<li>
<p><a href="https://hao.su/music">音乐搜索神器</a><br>
该音乐搜索引擎支持网易、QQ、酷狗、虾米、百度、咪咕。搜索后可试听、下载。音乐品质未知。</p>
</li>
<li>
<p><a href="https://www.tikitiki.cn/">自由的音乐</a><br>
看样式应该和上面那个网站差不多。支持QQ、网易、酷狗。搜索后可试听、下载。音乐品质一般。</p>
</li>
<li>
<p><a href="https://pan.baidu.com/">百度云</a><br>
百度云依旧是文件分享的聚集地,利用<a href="https://xilinjie.cc/">西林街</a>和<a href="https://www.panc.cc">胖次</a>进行资源搜索以后,多半可以找到自己需要的资源。当然这两个网盘搜索引擎<strong>不仅限于查找音乐资源</strong>。</p>
</li>
<li>
<p><a href="http://www.oppsu.cn/">OppsU!</a><br>
站内有大量网友分享的正版专辑文件,多以 iTunes 的专辑文件为主。当然也由于版权和一些众所周知的原因,该网站注册门槛非常高,只有每年特定时间才会开放注册。</p>
</li>
</ul>
<h3 id="软件-1">软件</h3>
<ul>
<li>
<p><a href="https://music.163.com/">网易云音乐</a><br>
在民谣、电音、翻唱方面,网易云的资源还是比较丰富的,免费流播,付费下载,可备不时之需。想要下载网易云的音乐拷贝到其他设备上听,但是现在网易云的音乐有自己的 NCM 格式怎么办?不妨试试<a href="https://github.com/yoki123/ncmdump">这个项目</a>的工具来去除音乐文件的保护,还原成正常的 mp3。</p>
</li>
<li>
<p><a href="https://www.spotify.com/">Spotify</a><br>
这是笔者目前主力使用的流媒体音乐平台。需付费(按区域选择不同,<a href="http://mts.io/projects/spotify-pricing/">价格不同</a>),跨平台,曲库以非华语音乐为主,当然主流的华语音乐也够应付大多数需求。</p>
</li>
</ul>
<h2 id="视频">视频</h2>
<h3 id="网站-2">网站</h3>
<h4 id="流播">流播</h4>
<p>自从发现了几个靠谱的流播网站以后,笔者的观影习惯逐渐从下载、屯资源,转变为了直接在线观看。拜国内宽带发展提速所赐,在线观看高清视频的障碍越来越低了。在此推荐一些可以直接流播真 · 高清影视资源的网站。</p>
<ul>
<li>
<p><a href="http://ddrk.me/">低端影视</a><br>
专为低端人口打造的影视流播网站。网站不是很追热点,站长的选片口味也不俗,特别是弄了一些豆瓣 Top250 的电影,值得一看。</p>
</li>
<li>
<p><a href="https://bowan.su/">播王</a><br>
为了弥补低端影视片库不足的问题,这个网站可以备用。</p>
</li>
<li>
<p><a href="https://www.duboku.net/">独播库</a><br>
这个网站也可以备用一下。</p>
</li>
</ul>
<h4 id="下载">下载</h4>
<h5 id="电影">电影</h5>
<ul>
<li>
<p><a href="http://yyets.com/">人人字幕组</a><br>
人人字幕组毫无疑问是国内数一数二的字幕组。字幕样式和翻译功底都算上乘。官网提供了各平台客户端的下载链接,以及相关网站的链接。</p>
</li>
<li>
<p><a href="http://www.zmz2019.com/">人人影视资源下载站</a><br>
免费注册会员,每日签到进行升级,除特殊影片可能会有等级限制查看,其他正常资源一律免费提供下载链接,登录后即可查看下载链接。</p>
</li>
<li>
<p><a href="http://cili001.com/">磁力站</a><br>
由于众所周知的原因,一部分资源不能在人人影视资源下载站提供下载,甚至不能提供下载链接,所以磁力站作为第三方搜索引擎,其数据基本涵盖了所有人人影视新旧资源的下载链接。你可以在这里找到几乎所有在人人影视字幕组发布过的资源链接。</p>
</li>
<li>
<p><a href="http://www.wuhaozhan.net/movie/list/">电影首发站</a><br>
原来的电影首发站进行了改版,个人感觉使用体验下滑了不止一个等级,随便用用即可。<br>
该站提供大量电影下载链接,无需注册,完全免费,使用迅雷等下载工具即可正常下载。笔者主要用来下载国产电影,该站也提供其他影视资源。</p>
</li>
</ul>
<h5 id="美剧">美剧</h5>
<ul>
<li>
<p><a href="http://www.zimuzu.io/">人人影视资源下载站</a><br>
人人字幕组除了提供含有中文字幕的电影下载之外,还有丰富的美剧资源。</p>
</li>
<li>
<p><a href="http://www.meijuhui.net/">美剧汇</a><br>
这是一个专注美剧的网站,貌似流播和下载都有提供。</p>
</li>
</ul>
<h5 id="纪录片">纪录片</h5>
<ul>
<li>
<p><a href="https://space.bilibili.com/22121599/#/">哔哩哔哩-纪录片之家</a><br>
哔哩哔哩站内有很多纪录片,而且很多视频的弹幕已经有野生翻译君助力。你可以在纪录片之家的 B 站首页进行查找,然后在线观看。</p>
</li>
<li>
<p><a href="http://www.daolan.net/index.php">道兰同好会</a><br>
该站是一个纪录片译制论坛,主要译制 NHK 纪录片。</p>
</li>
</ul>
<h5 id="动漫">动漫</h5>
<ul>
<li><a href="http://share.dmhy.org/">动漫花园</a><br>
一个朋友介绍给我的追番站点。不过如果你是 ACG 人士,应该也不需要我过多介绍。</li>
</ul>
<h5 id="生肉">生肉</h5>
<blockquote>
<p>生肉,网络用语。即“生的肉”,指的是,未进行加工(翻译)的ACGN作品,对应词汇是熟肉。含义为一般指动画的无字幕版。</p>
</blockquote>
<p>通常情况下,我们观看的视频资源都已经被字幕组翻译汉化,并将字母压制到了视频文件内。但不可避免地,总还是会有一些需要生肉资源的需求,这时候就需要通过国外的下载站进行下载了。
方法很简单,首先确保你知道影片的英文名称,如果不知道官方名称的话,可以通过<a href="https://movie.douban.com">豆瓣电影</a>进行搜索,然后获得该影视作品的英文名,然后就可以去下面的网站里找资源了:</p>
<ul>
<li>
<p><a href="https://katcr.co/">KICKASS</a><br>
综合性种子站,俗称“踢屁股”,新片老片应有尽有。由于众所周知的原因,多存几个镜像站比较保险:
<a href="https://katcr.co">https://katcr.co</a><br>
<a href="https://kat.sx/">https://kat.sx/</a><br>
<a href="https://kat.am">https://kat.am</a><br>
<a href="https://kickasstorrent.cr/">https://kickasstorrent.cr/</a></p>
</li>
<li>
<p><a href="http://rarbg.to/torrents.php">RARBG</a>
和 KICKASS 差不多,但是新片的发布速度貌似更快些,而且网页排版很好看。</p>
</li>
<li>
<p><a href="http://torrentz.eu/">Torrentz</a><br>
综合型种子搜索引擎,很多资源帝都爱用,被称为“万金油 BT 站”。</p>
</li>
</ul>
<h3 id="软件-2">软件</h3>
<ul>
<li>
<p><a href="https://potplayer.daum.net/">PotPlayer</a><br>
万能播放器。没有它打不开的视频文件,如果有,那多半是文件坏了。笔者有且只用它作为视频播放工具。</p>
</li>
<li>
<p>百度云文件下载软件<br>
众所周知百度云非 VIP 会员有下载限速。这里提供三款不限速的下载软件。为了避免怀孕,建议以自己的小号登录使用。笔者使用的是 PanDownload,非常好用,下载速度非常快,首推。<br>
<a href="http://pandownload.com/">PanDownload</a><br>
<a href="http://www.speedpan.com/">速盘</a><br>
<a href="https://github.com/proxyee-down-org/proxyee-down">Proxyee Down</a></p>
</li>
<li>
<p><a href="https://www.utorrent.com/intl/zh_cn/">µTorrent</a><br>
在国外下载站下载 BT 资源时,可能会需要使用 torrent 下载器,这里推荐使用 µTorrent ,此软件设计为在运行时使用较少的系统资源。至于下载速度快不快,主要看的是同时下载这一资源的人多不多,如果你对下载速度有执念,那还是去下载迅雷,然后付费会员吧。(摊手</p>
</li>
</ul>
<p>暂时写这么多,如果你有什么好的推荐不妨在评论区留言交流。</p>
V2ray配置Telegram的MTProto协议
https://acuario.xyz/posts/set-mtproto-for-telegram-via-v2ray/
2023-09-27T18:25:39+00:00
2018-08-16T06:58:28+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="前言">前言</h2>
<p>V2ray 是继 ShadowSocks 后又一个蓬勃发展、欣欣向荣的代理利器,目前支持多种传输协议。现在可以使用它设置 MTProto 协议,搭建 Telegram 的内部代理服务器,实现无需打开其他突破网络封锁的客户端即可正常通讯的目的。</p>
<h2 id="v2ray-的代理原理">V2ray 的代理原理</h2>
<p>v2ray 的代理原理和配置项的关系如下图:
<img src="https://i.loli.net/2018/08/15/5b73c180d5ef0.png" alt="v2ray原理图及配置关系"></p>
<p>p.s.上图为 v2ray v4.0 之前的代理原理图。v2ray v4.1+ 合并了输入输出配置项:</p>
<ul>
<li><code>inbounds = inbound + inboundDetour</code></li>
<li><code>outbounds = outbound + outboundDetour</code></li>
<li>为便于理解,你可以将上图 <code>inbound</code>、<code>inboundDetour</code> 视为各种不同的代理方式,全部定义在新版配置文件的 <code>inbounds</code> 配置项中,<code>outbounds</code> 亦同理。</li>
</ul>……
<h2 id="前言">前言</h2>
<p>V2ray 是继 ShadowSocks 后又一个蓬勃发展、欣欣向荣的代理利器,目前支持多种传输协议。现在可以使用它设置 MTProto 协议,搭建 Telegram 的内部代理服务器,实现无需打开其他突破网络封锁的客户端即可正常通讯的目的。</p>
<h2 id="v2ray-的代理原理">V2ray 的代理原理</h2>
<p>v2ray 的代理原理和配置项的关系如下图:
<img src="https://i.loli.net/2018/08/15/5b73c180d5ef0.png" alt="v2ray原理图及配置关系"></p>
<p>p.s.上图为 v2ray v4.0 之前的代理原理图。v2ray v4.1+ 合并了输入输出配置项:</p>
<ul>
<li><code>inbounds = inbound + inboundDetour</code></li>
<li><code>outbounds = outbound + outboundDetour</code></li>
<li>为便于理解,你可以将上图 <code>inbound</code>、<code>inboundDetour</code> 视为各种不同的代理方式,全部定义在新版配置文件的 <code>inbounds</code> 配置项中,<code>outbounds</code> 亦同理。</li>
</ul>
<p>v2ray 的的配置格式都是相同的,理论上不区分客户端和服务端,<code>客户端和服务器通用一种形式,只是实际的配置不一样。</code>v2ray 配置文件的配置项有以下几个部分:</p>
<pre tabindex="0"><code>{
"log": {},
"api": {},
"dns": {},
"stats": {},
"routing": {},
"policy": {},
"reverse": {},
"inbounds": [],
"outbounds": [],
"transport": {}
}
</code></pre><p>我们重点关注其中传入、传出和路由配置,即:<code>inbounds</code>、<code>outbounds</code>、<code>routing</code>。</p>
<ul>
<li><code>inbounds</code> 和 <code>outbounds</code> 定义多种不同的传入、传出方式。</li>
<li>自定义不同的传入和传出方式,然后用路由(<code>routing</code>)进行绑定,就可以实现定制化代理。</li>
</ul>
<p>下面举几个栗子:</p>
<ol>
<li>仅用来突破网络封锁:客户端 <code>outbounds</code> 设置一个 VMess 协议传出、服务端 <code>inbounds</code> 设置一个 VMess 协议传入,服务端 <code>outbounds</code> 设置一个 freedom 方式传出。这样,客户端与服务端将使用 VMess 协议加密流量突破网络封锁,而服务端访问被封锁网站没有特殊加密,使用正常网络传输协议。</li>
<li>服务端配置其他的传入、传出协议实现不同于的传输需求。比如服务端添加一组 MTProto 协议对应的传入、传出方式,即可以使用 Telegram 内部代理。或者使用 shadowsocks 协议传入,再用 vmess 协议传出给下一个服务端,实现多级代理等等。</li>
<li>多种传入、传出方式可以共存,打上标签(<code>tag</code>)以后,用路由(<code>routing</code>)实现自由绑定,所以仅使用 v2ray 就可实现多种方式的传输需求,比如同时支持 VMess、Shadowsocks、MTProto、Socks 协议进行通讯。v2ray 支持<a href="https://www.v2ray.com/chapter_02/02_protocols.html">多种协议</a>,发挥你的创造性去使用吧。</li>
</ol>
<h2 id="mtproto-的配置">MTProto 的配置</h2>
<p>v2ray 的<a href="https://www.v2ray.com/chapter_02/protocols/mtproto.html">官方手册</a>提供了不完整的样例配置</p>
<h3 id="传入代理">传入代理</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">"inbounds"</span><span class="err">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"tg-in"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"port"</span><span class="p">:</span> <span class="mi">443</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"mtproto"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"users"</span><span class="p">:</span> <span class="p">[{</span><span class="nt">"secret"</span><span class="p">:</span> <span class="s2">"b0cbcef5a486d9636472ac27f8e11a9d"</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>传出代理:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">"outbounds"</span><span class="err">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"tg-out"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"mtproto"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>路由:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">"routing"</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"rules"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"field"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"inboundTag"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"tg-in"</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outboundTag"</span><span class="p">:</span> <span class="s2">"tg-out"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="配置文件示例">配置文件示例</h2>
<p>这里提供一个主要使用 VMess 协议突破网络封锁,额外支持 MTProto 协议实现 Telegram 内部代理的配置文件,其中:</p>
<ul>
<li>服务端设置的端口务必加入服务器防火墙例外,否则可能无法正常连接</li>
<li>UUID 可以在 <a href="https://www.uuidgenerator.net/">Online UUID Generator</a> 网站生成</li>
<li>用户密钥可以使用命令 <code>openssl rand -hex 16</code> 生成</li>
</ul>
<h3 id="服务端配置">服务端配置</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"inbounds"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"port"</span><span class="p">:</span> <span class="err">填写</span> <span class="err">VMess</span> <span class="err">协议监听端口</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="err">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"vmess"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"clients"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"id"</span><span class="p">:</span> <span class="s2">"填写UUID,不要去掉引号"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"level"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"alterId"</span><span class="p">:</span> <span class="mi">64</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"tg-in"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"listen"</span><span class="p">:</span> <span class="s2">"0.0.0.0"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"port"</span><span class="p">:</span> <span class="err">填写</span> <span class="err">MTProto</span> <span class="err">协议监听端口</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"mtproto"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"users"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"secret"</span><span class="p">:</span> <span class="s2">"填写用户密钥,不要去掉引号"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outbounds"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"freedom"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"blackhole"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"blocked"</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"tg-out"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"mtproto"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"routing"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"rules"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"field"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"ip"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"geoip:private"</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outboundTag"</span><span class="p">:</span> <span class="s2">"blocked"</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"field"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"inboundTag"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"tg-in"</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outboundTag"</span><span class="p">:</span> <span class="s2">"tg-out"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="telegram-内部代理设置">Telegram 内部代理设置</h3>
<p>将服务器的 IP 地址、配置的 MTProto 协议监听端口、用户密钥填入 Telegram 的代理设置中即可使用。或者使用构造链接在 Telegram 内部打开进行自动设置:</p>
<p><code>https://t.me/proxy?server=服务器IP地址&port=服务器MTProto协议监听端口&secret=用户密钥</code></p>
<h3 id="客户端配置">客户端配置</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"inbounds"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"port"</span><span class="p">:</span> <span class="mi">1082</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"listen"</span><span class="p">:</span> <span class="s2">"127.0.0.1"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"socks"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"auth"</span><span class="p">:</span> <span class="s2">"noauth"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"udp"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"ip"</span><span class="p">:</span> <span class="s2">"127.0.0.1"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outbounds"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"vmess"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"vnext"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"users"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"alterId"</span><span class="p">:</span> <span class="mi">64</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"security"</span><span class="p">:</span> <span class="s2">"auto"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"id"</span><span class="p">:</span> <span class="s2">"填写 UUID 与服务端一致,不要去掉引号"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"port"</span><span class="p">:</span> <span class="err">服务端</span> <span class="err">VMess</span> <span class="err">协议监听端口</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"address"</span><span class="p">:</span> <span class="s2">"服务端 IP 地址,可以去掉引号"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"freedom"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"direct"</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"protocol"</span><span class="p">:</span> <span class="s2">"blackhole"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"settings"</span><span class="p">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"tag"</span><span class="p">:</span> <span class="s2">"blocked"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"routing"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"rules"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"field"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"ip"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"geoip:private"</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outboundTag"</span><span class="p">:</span> <span class="s2">"direct"</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"field"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"domain"</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"geosite:cn"</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"outboundTag"</span><span class="p">:</span> <span class="s2">"direct"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"log"</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nt">"loglevel"</span><span class="p">:</span> <span class="s2">"warning"</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<p>参考链接:
<a href="https://www.v2ray.com/chapter_02/01_overview.html">v2ray 配置文件格式</a>
<a href="https://ntgeralt.blogspot.com/2018/08/telegramv2raymtproxy.html">让 Telegram 连接 V2ray 服务端 mtproxy 协议</a></p>
《拜訪革命》读书笔记
https://acuario.xyz/others/the-portrait-of-revolution-clip/
2023-09-27T18:25:39+00:00
2018-06-06T22:04:25+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>第 11 頁<br>
似曾相識的開端,踏出截然不同的路徑,兩厢對照,變革的命運更加清晰。對當權者而言,如果開放可以延續權力,他便鬆手,如果鐵腕能夠穩固執政,他便握拳。然覆手雲雨之間,時機、地理、民意、外力,多少偶然互相撞擊,革命的軌道像雲霄飛車一樣不知道下一秒的起落。</p>
<hr>
<p>第 12 頁
許多美國人不關心世界,連護照都沒有,但這並不妨礙美國成為頭號自由之邦。但是否正因如此,以強烈排外為面貌的右翼風潮,近些年在美國、在歐洲急速抬頭?外交政策的制訂雖是精英之事,若大眾與精英之間嚴重脫節,英國脫歐、川普上台之類的事情就會一再震驚世界。</p>……
<p>第 11 頁<br>
似曾相識的開端,踏出截然不同的路徑,兩厢對照,變革的命運更加清晰。對當權者而言,如果開放可以延續權力,他便鬆手,如果鐵腕能夠穩固執政,他便握拳。然覆手雲雨之間,時機、地理、民意、外力,多少偶然互相撞擊,革命的軌道像雲霄飛車一樣不知道下一秒的起落。</p>
<hr>
<p>第 12 頁
許多美國人不關心世界,連護照都沒有,但這並不妨礙美國成為頭號自由之邦。但是否正因如此,以強烈排外為面貌的右翼風潮,近些年在美國、在歐洲急速抬頭?外交政策的制訂雖是精英之事,若大眾與精英之間嚴重脫節,英國脫歐、川普上台之類的事情就會一再震驚世界。</p>
<hr>
<p>第 13 頁
「走到某處邊界,總想看看,邊界背後是什麼,於是一路走下去。」</p>
<hr>
<p>第 20 頁<br>
我好奇地追問篤信神明的尼泊爾人,為何支持不信宗教的「毛澤東主義」。「哦,不,這沒有關係,他們為國家做好事。」私營旅行社的庫馬拉說,毛派改變了窮苦大眾的命運,他押寶毛派主導的政府將帶來新的穩定、新的生意。</p>
<hr>
<p>第 21 頁<br>
紅色到來之前,尼泊爾經歷了血色。
一九九六年起,普拉昌達領導毛派武裝與政府展開長達十年的內戰,造成約一萬三千人死亡,兩萬多人逃離家園,超過八百人失蹤。
有西方記者稱毛派武裝曾在加德滿都街頭射殺不服從命令的計程車司機,而他們雇傭十六歲以下的娃娃兵,也不是什麼秘密。萬幸,毛派最後放棄武力進占加德滿都, 一紙協議,國人止血。</p>
<hr>
<p>第 36 頁<br>
整個尼泊爾百分之八十以上的人務農,其中一半人口掙扎在聯合國劃定的貧困線以下。土地掌握在極少數世襲地主手中,耕者衹賺取微薄的酬勞。</p>
<hr>
<p>第 42 頁<br>
「兩伊戰爭對伊朗,相當於中國的朝鮮戰爭。」一名常駐當地的中國記者分析說,都是新生政權第一次遭遇對外戰爭,必傾性命一搏。何梅尼曾經流亡伊拉克宗教聖地納吉夫。迫於伊朗國王壓力,伊拉克總統薩達姆·海珊(Saddam Hussein)逐他出境。雖轉投巴黎,如魚得水,但革命成功後,何梅尼沒有忘記海珊落井下石,而海珊更惦記著在鄰國政權更迭時乘虛而入。</p>
<hr>
<p>第 44 頁<br>
巴勒維國王的父親禮薩廢除了面紗。這位騎兵出身的將軍不以伊斯蘭教為生活準則,相信伊朗的出路在於全面西化。二十世紀初,東方文明國度或主動或被動,認可現代化道路的面貌就是西方化告別面紗,就是告別過去與落後。
二十世紀七〇年代,在反對巴勒維國王的抗議中,許多城市婦女主動包上頭巾——不是因為贊同伊斯蘭生活方式,而是表達對王權的不滿和對宗教女性的同情。但是她們沒有料到,推翻王權之後戴不戴面紗不再是一個選項——底層宗教熱情釋放出來,鋪天蓋地呼應何梅尼政教合一的設想。</p>
<hr>
<p>第 45 頁<br>
我在伊朗的時候,趕上巴西世界盃半決賽。伊朗人酷愛足球,但是政府有令,不得聚眾圍觀。二〇〇九年事件以來,「人多」是個敏感詞,足球也變得政治起來。二〇一〇年南非世界盃,伊朗國家隊球員手腕上纏著綠絲帶上場,表達對穆薩維的支持。但既然政府有令,大部分伊朗人就在家關起門看電視。</p>
<hr>
<p>第 48 頁<br>
艾哈邁迪內賈德借助打擊社會自由風氣,擴大了革命衛隊和巴斯基的權力,著裝要求更嚴,言論受到空前壓制。愛國主義也被用來挑釁反對者。他積極尋回兩伊戰爭遺骸,特別安置在青年男女偷偷約會的公園和大學校園,多次引發抗議。德黑蘭人說,別人「種樹」,艾哈邁迪內賈德「種烈士」。</p>
<hr>
<p>第 49 頁<br>
「死亡、監禁、抓捕、毆打,所有這些耗盡了我們的能量。」達拉說。即便是二〇一一年阿拉伯抗議風潮驟起,伊朗也沒有重演綠色革命。桌上其他人紛紛點頭。人心疲累,現在學生們在一起不大談論政治。</p>
<hr>
<p>第 50 頁<br>
紮小辮的舞台劇導演,為這過時的藝術家髮型蹲過幾天監獄。最近他排了一齣劇,按達拉的說法,「分明是舞蹈」,但不能叫「舞蹈」,因為伊斯蘭政府嚴禁跳舞。小辮改了名字叫「韻律活動」,希望掩人耳目通過審查。當他們議論政府管制的愚蠢時,臉上會露出興奮,你可以感受到他們的苦悶和無奈,但也夾雜一絲遊戲的快樂。</p>
<hr>
<p>第 51 頁<br>
美國人介紹達拉時愛說:「這個姑娘為了信仰勇敢鬥爭,終於抵達美利堅。」可是達拉並不認同自己是什麼「英雄」,只是「出現在錯誤的地點(被便衣聽到電話)」。以美國公民身分出入德黑蘭並非難事,她說,好多伊朗毛拉(mullah)政客、富商的孩子都持有美國護照,國籍不會成為不能入境的理由,只要你「不惹事」。</p>
<ul>
<li>毛拉泛指精通伊斯蘭神學與律法的學者。</li>
</ul>
<hr>
<p>第 51 頁<br>
玫瑰園正式竣工還是在兩伊戰爭之後,但「商場」概念的引入者,卻是末代國王巴勒維。他希望借此打擊巴札商人與伊斯蘭教士的勢力。「巴札」指的是中世紀以來中亞、北非的集市,不僅僅是貿易場所,更是當地商人、手工製造者和銀行(或借貸者)的一張關係網。在伊朗,巴札控制著國內三分之二的批發銷售,也把持著本地毯子和堅果的出口。巴札商人自然不喜歡外國商品進來競爭。國際封鎖傷害了伊朗産品外銷,但實際效果又保護了巴札商人在國內的壟斷。
幾個世紀以來,巴札商人捐錢給教士,教士們負責將伊斯蘭教義解釋得有利於他們的生意和生活模式。很多清真寺就建在巴札裡面。「金錢與教義」結盟,在一八九一年發起「菸草抗議」,抵制吸食英國商人專營的水菸,在一九〇五年參與立憲革命,削弱國王特權。而一九七九年反對國王的革命中,這種聯盟的效果更是決定性的。</p>
<hr>
<p>第 53 頁<br>
走私在今天伊朗經濟的比重難以計算。後來我漸漸發現, iPhone 手機在德黑蘭很普遍,街上還有蘋果專賣店,彷彿整個從美國加州鑽地道大搖大擺地走了進來。店員穿的也是藍色 T 恤,胸前懸掛白色卡片。但誰都知道,蘋果和伊朗尚未「建交」。倒賣外國産品的走私生意,經手者很可能是掌握特權的革命衛隊,也可能跟巴札商人有關。錢,令政治界線模糊,利益圖譜變得複雜。</p>
<hr>
<p>第 54 頁<br>
「你想不到他們會託我從美國帶什麼。」達拉每次回國,朋友們點名要的是「真的星巴克紙杯、原裝可口可樂」。玫瑰園商場有店鋪賣仿製的星巴克馬克杯,被當作高檔工藝品擺在黑絲絨軟墊上展出。而伊朗的可口可樂,來自一九七九年美國人落跑時留下的配方和工廠。「見過世面」的米夏講了一個更好笑的故事:他在義大利的時候,接待過父親的同事和他的兒子。這對伊朗父子每天都點名要吃麥當勞。「我勸他們義大利菜好吃,但他們只想吃麥當勞。」一次去鄉村,沒有麥當勞,不得不吃了一回當地餐。伊朗父子承認非常美味,可是第二天回到城裡,他們又要求吃麥當勞。米夏很生氣,當真實世界攤開在眼前,伊朗老鄉竟執著尋找臆想中的那一個。他們對那個世界的想像相當狹隘,縮小到美國,縮小到美國流行文化,縮小到起士漢堡。</p>
<hr>
<p>第 55 頁<br>
現在,商場二樓正對何梅尼和哈米尼畫像的地方,貼著「免費無線上網」。幾乎所有人都能嫻熟地使用捷克產的翻牆軟體,越過政府在網際網路上設置的障礙,連最高領袖本人都在「被遮罩」的海外社交媒體上開了帳號。技術的發展似乎站在了反抗者這一邊,但當局並不打算放棄。如果沒有特殊軟體,直接在伊朗網際網路上搜索西方歌曲、電影或敏感政治,都會被立即連結到「伊斯蘭政府網站」的主頁。有時你覺得伊朗人與外面的世界就隔了一層紙,但那層紙是鐵打的。</p>
<hr>
<p>第 57 頁<br>
何梅尼的學生和長期追隨者拉夫桑賈尼(Akbar Hashemi Rafsanjani),成了哈米尼的第一任總統,被稱為「伊朗鄧小平」。在許多發展中國家,「鄧小平」是「市場經濟啟動者」的代名詞。兩伊戰後百廢待興,拉夫桑賈尼推出兩個「五年計劃」,對超過一千家國營企業實行私有化。伊朗出現了股票市場、自由貿易區,農業國家開始向工業化轉變。</p>
<hr>
<p>第 62 頁<br>
達拉鬥爭經驗不足,米夏更像是在抗議洗禮中長大。在德黑蘭藝術大學念書時,他崇拜一個高大壯實的學長——差不多有兩公尺高。米夏說起來的時候,還要向上仰望。學長是政治活躍分子。一天午餐,學長突然來到食堂,說不要吃今天的肉,那是國王時代就存在冰箱裡的。肉怎麼可能保存三十年?學長拿出從食堂偷來的一條牛後腿, 一看印章,真是巴勒維時代的。不管怎麼說,大家發現那天午餐的味道確實古怪。學長號召絕食,敲盤子繞著校園遊行。堅持三天,校方道歉承諾改善伙食。那一次,米夏看到了反抗的力量。</p>
<hr>
<p>第 69 頁<br>
在他記憶中,綠色革命的結束,不僅僅因為政府的鐵腕鎮壓,還因為「抗議者和政府都懼怕國家動盪,上下一起停了」。
也許我流露了出些許驚訝,他接著說:「伊朗人和中國人一樣害怕國家動盪。」雷拉茲曾經是一家國有企業廠長,很早就到廣州考察過,對中國這些年的情況很熟悉。他仰慕中國經濟成就,十年前就預言中國應該在國際關係中領頭。</p>
<hr>
<p>第 77 頁<br>
賈維爾笑了:「這真得怪他們。」他在我的筆記本上畫了一個「馬斯洛需求層次金字塔」,頂層是「自我成就」,最底層是「呼吸、食物、性、住房、健康」。他在「性」上劃了個叉:「我們的政權非常聰明,管住人最基本的需求,於是我們滿腦子就剩下這些,其他什麼都不想了。」
伊朗禁止公開戀愛。儘管女人戴面紗、男女授受不親等伊斯蘭習俗,在一九七九年革命之前就在伊朗社會存在,但是革命之後才寫進法律,出動風紀警察監管。性禁忌還常常與政治聯繫在一起。異議者不管做了什麼,對他們的譴責首先跟性醜聞扯上關係,並迫使他們向公眾懺悔。「我們的傳統文化還是比較保守, 一提『性醜聞』,大家馬上覺得這是個壞人。」賈維爾說。
性有時還比政治更危險。賈維爾有一本喬治·歐威爾《一九八四》——這本書刻畫了一個處處受到監管的虛擬社會,在伊朗翻譯並出版的波斯文版,刪去了幾處溫斯頓與茱麗葉溫存的性描寫,其他都保留了下來。</p>
<hr>
<p>第 80 頁<br>
當地朋友說反美標語不只我看到的這些,還有直白樸實些的,比如「我們把美國踩在腳下」等等。但終究沒有我想像中滿街「反美話語的海洋」。十多年前伊朗學者搞過一次民意調查,百分之七十四受訪者願意跟美國談判,百分之六十四支持跟美國復交。結果,組織調查的人被關起來了。
伊朗的「性禁忌」常跟「西方文化滲透」聯繫在一起。何梅尼說:「公共場合男女混雜,是外國人的陰謀,用來瓦解穆斯林青年的意志。」「外國」很多時候單指美國。</p>
<hr>
<p>第 82 頁<br>
賈維爾始終沒找到「百分之三十五的性壓抑」數據的出處。倒是伊朗議會在二〇一四年夏天,發佈一份八十二頁正式調查報告,承認百分之八十伊朗未婚女性有男友,中學生談戀愛都十分普遍。受訪的一萬四千兩百名學生中,百分之十七承認同性取向。本地媒體對這份報告不做討論,我是在英國《經濟學人》雜誌網站上讀到的。</p>
<hr>
<p>第 83 頁<br>
地鐵隧道又深又廣,戰時也可作防空洞。末代國王時期做了規劃,承包給一家法國公司,可還沒動工,革命就爆發了,於是被迫擱置下來,直到伊斯蘭共和國也生出現代交通的煩惱,國王時代的地鐵設計圖才被翻出來,請中國長春和上海的公司來參與建設。</p>
<hr>
<p>第 97 頁<br>
什葉派與遜尼派的分歧,概括來說,就是先知穆罕默德歸真之後,誰有資格成為繼任者。什葉派推崇先知的女婿阿里。阿里遇刺,他的兒子胡笙全家也遭主流派伏擊,慘遭滅門。此後什葉派無論從人數還是影響力,一直處於弱勢,演化出一套自己的信仰與智慧,與遜尼派有共識,也有差異。「胡笙的血」、千年的冤屈和復仇,構建了什葉派的情感共同體。薩法維王朝立什葉為國教, 一個原因是為了對抗強大的鄂圖曼帝國,與那裡的遜尼派切割。但立教之初,伊朗國內教法學家不夠,要從敘利亞、黎巴嫩借來,填充清真寺和學校。</p>
<hr>
<p>第 117 頁<br>
第納爾是目前世界上許多國家的貨幣名稱,但幣值各不相同。此稱呼源自古羅馬帝國的銀幣Denarius。</p>
<hr>
<p>第 118 頁<br>
一九二〇年,英國人取得對伊拉克的委任統治,預見到統治成本太高,只要了十年委任期(美軍或許早該料到自己的駐紮期限)。英國人臨走前劃定伊拉克、科威特邊境,以各自的椰棗林終點為界。結果當天夜裡,伊拉克、科威特兩邊都開始瘋狂補種椰棗樹。邊界爭議,正是海珊後來入侵科威特的理據。</p>
<hr>
<p>第 123 頁<br>
伊拉克軍警打算驅散抗議者,不是因為集會內容,而是因為事先沒有申請。伊拉克新憲法賦予公民「集會、抗議的自由」,但必須提前向內政部申請,以便佈置警力,維持秩序。我向薩拉丁求證這件事,他說審批程序不是特別複雜,如今,抗議議員、抗議政府,上街遊行喊口號,理論上並不困難,但有些行動註定不會被批准,比如二〇一一年受到「阿拉伯之春」影響,伊拉克當地遜尼派抗議馬利基政府,還是遭到了軍警拘捕打壓。
「跟我說說,言論自由了有什麼好處?」
沒想到,這一問薩拉丁竟哀傷起來:「我們說什麼都行,但解決不了問題。」
「那沒有行嗎?」
「我想只會更糟。重要的是,今天每個伊拉克人看待自己不同了。」</p>
<hr>
<p>第 126 頁<br>
美軍已經撤走,再不見灰綠色迷彩。十年治後,巴格達地面上看不出明顯的美國痕跡。雖然美式速食在中東非常普遍,但巴格達沒有麥當勞。所有人相信,它開張的第一天會被炸成「ground zero」(核爆點,亦指「九一一 」廢墟) 。一般餐館裡依舊沒有咖啡,只提供「伊拉克茶」,阿拉伯人愛喝的紅茶。
但是你也會看到,很多伊拉克人用最新款蘋果手機。由於免稅(或者走私),這裡的售價跟美國本土幾乎一樣。初次見面,我問美聯社攝影師穆罕默德,能不能找張巴格達全圖。「誰還用紙質地圖,用 Google 地圖吧。」他邊說邊在蘋果手機上給我示範,「伊拉克用的全是美國衛星,上美國網站快著呢。」</p>
<hr>
<p>第 132 頁<br>
在東方,強權仍然受到推崇。而那些憎恨強權的,往往只是憎恨自己沒有成為強權。</p>
<hr>
<p>第 134 頁<br>
西元8世紀阿拔斯王朝的「外文翻譯局」智慧宮,據說遺址仍在,但參觀要事先向文化部申請,拿著鑰匙開門進去。當時,在阿拉伯人主持下,外族人和新進穆斯林把無數希臘著作翻譯成阿拉伯文,無意中為後來的歐洲文藝復興留存了火種。但是,阿拉伯人對希臘著作的翻譯有選擇,取捨標準是教育性,或者說實用性。所以,他們孜孜不倦地在哲學和科學書籍中尋找真理,卻懶得理會希臘詩歌、戲劇和歷史。最遭忽視的,是地理和政治。有學者認為,就在這裡,伊斯蘭與西方現代文明的分野出現了:亞里斯多德的大部分作品都被翻譯,但巴格達的阿拉伯人禁止引進他的《政治學》。這本書論述了國家的性質,統治者與被統治者的關係。這個概念沒有釐清,導致伊斯蘭至今沒有做到政教分離。
一本書的缺失,阻礙了中東民主化進程,這個說法未免誇張。曾經向歐洲輸出文明的伊拉克。如今迎來了美國人的 nightclub,卻還沒有真正的民主。「現代性孕育穩定,但現代化過程卻滋生動亂」,杭廷頓的後半句,恰恰是今日中東、今日伊拉克的現實。</p>
<hr>
<p>第 139 頁<br>
中國在伊拉克的大型計畫很難招到本地工程師。高級技工集中在巴格達,不願離開家人去外省。而中國工人們,無一不是跋涉兩萬多公里,把家人留在身後。
在伊拉克的中國人,幾乎人人背負這樣的故事,無論使館官員,還是建築工人。中國駐伊拉克使館,全館上下衹有大使夫人一名異性。常駐當地的一對中國記者夫婦,辦公室擺著兒子一歲時的全家福,而他現在已經兩歲,由親戚照料。
人人都以暫時犧牲換個好一點的將來。為了將來,眼前什麼是可以犧牲的呢——自由?歡樂?親情?愛情?青春?矛盾的是,這些犧牲,往往是為了家庭的共同未來,而放棄的,首先是與家人共處的歡愉。中國人的幸福,似乎不在眼前。
外國媒體常常感慨,中國人好像「怪物」,不惜抛家捨命。我向一名在伊拉克工作三年的中國企業領導提起這種評論,他不否認:「我也認為這樣不好,因為是被迫的。但是,過去三十年,中國能夠實現超常發展,必定因為有人付出了代價。」</p>
<hr>
<p>第 154 頁<br>
跟這裡的中國人交談,發現他們大多喜歡杜拜,而吸引他們留下來的,首先是免稅、物質豐富,其次是不談政治。淑容結合中西醫之長,在這裡已行醫九年。問她在杜拜找到了什麼,答:「自由。她的前半生在希臘和美國度過,這個回答令我疑惑:「美國和希臘沒有自由嗎?」「不一樣,在美國,病人走進我的診所,我都得考慮一下他是民主黨還是共和黨,話別說錯了,而杜拜的政治氣氛太弱了。」在她看來,遠離政治,才是自由。</p>
<hr>
<p>第 195 頁<br>
艾明大學畢業時打定主意不在政府系統工作,「因為沒有『關係』」。他說,在國家部委或國營企業找份好工作,首先要在複雜的資格考試中獲得高分。但他認識一些「不知道怎麼可能考及格」的同齡人,捧到金飯碗。「『背景』比能力更重要,進去之後也要憑關係上去。」所以他選擇留在民營企業——爸爸工作的醫藥公司。
「國家富裕了,但錢都到了執政黨口袋裡。」艾明抱怨正義發展黨的「關係網」把持經濟利益。
眼下他打算跟幾個朋友創業,做電信資料服務,儘管這跟他的化工系學位不搭界。土耳其電信被國營資本和大財團壟斷,我小心翼翼問艾明,涉足這個領域是不是得「認識什麼人」?他難為情地笑了:「哈哈,當然。」他的「關係」來自反對黨。我也笑了,人們跟「關係」的關係常常很複雜。</p>
<hr>
<p>第 197 頁<br>
父親說話平和。他認為每個家庭成員的看法因記憶而不同。六十八歲的外婆經歷過土耳其最動盪的時期,上世紀九〇年代庫德人四處製造恐怖襲擊,二十多年來造成四萬人死亡。七、八〇年代,土耳其左右兩派政黨爭權,街頭每天發生劫掠、燒殺。自凱末爾的政黨一九五〇年輸掉選舉以來,土耳其一直由不同黨派組成的聯合政府經營,分分合合,風波不止,直到正義發展黨拿下議會半數以上席位, 一黨包攬政府,才穩定下來。外婆這般年紀的人,自然珍惜這十來年的好日子。
這讓我想起,母親是土耳其人的英國女記者阿勒夫·斯科特(Alev Scott)寫過一個細節:今天伊斯坦堡治安很好,但土耳其人對「亂」的恐懼根深蒂固。她看見房東執意把木製百葉窗換成鋁合金的,忍不住笑出來,「好像夏天裹著棉被」。但是只有經歷過動盪的人,才能理解這份恐懼。
父親親歷了一九八〇年政變,確切來說,是軍隊鎮壓學生反政府行動,傳言數萬名大學生慘死,但這在土耳其仍是個禁忌話題,確切數字不詳。所以當艾明走向蓋齊公園,父親就知道政府不會忌憚動武,跟上去保護兒子,卻終究沒有讓女兒去現場。博拉薩到現在都生爸爸的氣。
艾明和妹妹打記事起,大部分時間生活在厄多安時代。他們經歷的土耳其,既沒有亂過,也沒有窮過,通過衛星頻道網際網路,他們的生活跟歐洲年輕人零距離。艾明幾個月後要去奧地利,跟我的那位朋友周遊。二〇〇一年的經濟危機只是小插曲,博拉薩說「根本不記得」。她無法感念厄多安的好處,衹討厭他侵犯「個人自由」——比照歐洲各國, 一個政府搞好經濟不是理所應當嗎?「這個老傢伙怎麼不明白,我們是不一樣的人?」如果說厄多安開創了富強的土耳其,他卻認不出富強起來的土耳其人。</p>
<hr>
<p>第 199 頁<br>
土耳其三十年來的經濟發展,成就了人們對命運的不同選擇。即便是一家人,有的到大城市發展,有的留在農村。整個國家在進步,不同人群的物質差異在縮小,但生活方式和精神世界的差異並沒有消失,當他們見面時,這種差異就更明顯。</p>
<hr>
<p>第 206 頁<br>
道別艾明一家,我深感不安,外婆可能會反感這個外來者挑起家庭爭論。沒想到,合影的時候,她一隻手暖暖圈住我後腰,歡迎我下次再來。爸爸說,家裡經常爭論,「才是民主」。
「看來你家裡,外婆是唯一會投票給厄多安當總統的人了?」我問艾明。他開「爸爸公司的車」送我回酒店。「不見得。」小夥子狡黠一笑。上次地方選舉時,他身在外地不能投票,外婆替他去了投票站,以自己的名義投給反對黨。外婆說,未來不是她的,是外孫的,要聽從他的選擇。</p>
<hr>
<p>第 217 頁<br>
托克維爾在《舊制度與大革命》中有這麼一句結論:「對一個糟糕的政府來說,最危險的時刻,是它開始了改革。」他認為,路易十六時期的法國實際上比之前更富裕、更開明,可是革命發生的時候,往往不在人民生活越來越壞的年頭,相反,是在人們發現暴政壓力減少、鐵鉗慢慢鬆開的契機——他們開始相信,自己有能力推翻暴政。</p>
<hr>
<p>第 260 頁<br>
我眼前出現了更大的圖景:沙烏地阿拉伯給塞西政府十倍於美國的援助,拉攏埃及。卡達與沙烏地阿拉伯是對頭,接收與埃及現政權勢不兩立的穆兄會青年。這兩個國家都坐在從天而降的巨大能源財富上,隱隱的不安敦促著它們尋求長久的政治影響力。上一次,阿巴斯和瓦利德相逢在國家內部融合的舞台上,眼下,他們又出現在地區角力的棋盤上。這盤棋上所謂的「外來勢力」,主角不再是西方,而是同為阿拉伯族裔的鄰居們。從這個意義上說,大概有邊界有競爭,「外部勢力」就不會消亡吧。</p>
<hr>
<p>第 274 頁<br>
革命沒有發生在埃及經濟陷入困難的時候,相反,恰恰是在埃及人經濟條件改善、對自身權利也愈加關注的階段。陳舊的統治結構遭遇新的變化時,如摧枯折腐。
二〇一一年二月十一日傍晚,我在拉姆西斯酒店房間傳稿,窗外傳來潮水般的掌聲和歡呼——不像是抗議。打開電視一看:穆巴拉克下台了!我和攝影師趕緊奔出去,立刻被歡慶的隊伍裹挾,我對著鏡頭說話時,竟被旁邊的人拉起手跳舞, 一面埃及國旗覆蓋了鏡頭。我們搭車去穆巴拉克總統府,司機居然不收錢:「為了革命!」他打了個勝利的手勢後,消失在狂歡的夜裡。沒有人到拉姆西斯酒店鬧事。人們主動清理垃圾,維持交通。十天後,在我離開時,沒有聽說任何打砸事件。
持續動盪打擊了旅遊、出口、外資幾乎所有行業,二〇一一年以來,埃及經濟發展急劇減緩,與革命爆發的前一年相比,多了一百三十萬失業者,其中近七成是持有高校畢業證的年輕人。各種街頭運動中的死亡人數,超過了二〇一一年的「倒穆」運動。</p>
<hr>
<p>第 279 頁<br>
卡薩姆的妻子原本默默坐在牆角,這時開始高聲譴責穆兄會禍亂國家,她斬釘截鐵地說:「『一二五』不是真正的民眾革命,『六三〇』才是!」過去三年,兩個日子對埃及人尤為重要:二〇一一年一月二十五日,要求穆巴拉克下台的遊行爆發;二〇一二年六月三十日,軍方出手鎮壓穆斯林兄弟會, 一星期後逮捕了第一位民選總統莫爾西。然而,埃及人對這兩個日子的定義卻迥然不同:前一天,另外一個埃及人告訴我,「六三〇」是假民眾之名的兵變,「一二五」才是「純潔的革命」。不同定義,未必出自對穆兄會的好惡,而是每個人對錯綜局面的不同解讀。</p>
<hr>
<p>第 284 頁<br>
波蘭歷史學家亞當·米奇尼克(Adana Michnik)說過,革命有兩個階段,第一為了自由,第二為了權力。第一階段煥發出人性最好最純潔的一面,第二階段卻釋放出壞的一面。</p>
<hr>
<p>第 291 頁<br>
自一七九八年拿破崙在埃及登陸以來,歐美影響像一把利刃,不斷地塑造著中東,打磨出一個現代社會的模樣,但也留下不少硬傷(如殖民者不合理的邊界劃分) 、更不用說揮之不去的心靈創痛至今縈繞阿拉伯人、伊朗人、土耳其人的問題還是, 一種曾經燦爛的文明如何面對強盛的西方?</p>
<hr>
<p>第 292 頁<br>
幾百年來,各種「主義」試圖為伊斯蘭文明復興找到一條出路。但二〇一一年發生的變革,卻沒有意識形態主宰。它也不像是關於「哪一種制度更適合」的嚴密論證,而是一聲樸素的生活要求:「別人有的,我也要:自由、公正、尊嚴。」</p>
<hr>
<p>第 302 頁<br>
滿眼領導人畫像這道風景線,利比亞有,突尼西亞、埃及、巴林、敘利亞、葉門……最近如多米諾骨牌一樣發生騷亂的國家都有。畫中領導人或微笑或沉思,只是眼睛都不會平視地上的民眾。目光高於觀看者的角度,令他們顯得深邃,總是知道民眾不知道的事情。只可惜那些密佈的畫像,更像是江湖術士的符咒,關鍵時刻竟然失靈,埃及人只用了十八天,就扳倒了穆巴拉克,貼了三十多年的畫像一夜隨風去。從街道,從教室,從餐廳,從超市,從藥房,他都剛剛離去,「穆巴拉克橋」、「穆巴拉克地鐵站」立時換了名字。
二〇〇八年金融海嘯的時候,有人半開玩笑地提出「星巴克理論」——星巴克咖啡館越多的地方,遭受這輪危機衝擊的情況越嚴重。理由是,星巴克分店往往靠近金融街、房産交易中心,而銀行倒閉、房產泡沫正是這次危機的導火線。如此說來二〇一一年刮起的中東變革海嘯,是否也見到了一個「畫像理論」?領導人畫像頻密的地方,局勢註定不穩。因為通街畫像的本質是「少數人統治多數人」的模式,正是此番民間怒潮所指。
伊斯蘭教本來不容忍「畫像」、「造像」等一切有形的裝飾。清真寺裡絕對見不到人形圖案。教義認為,真主無形,因此無所不在。
但利比亞人向領袖致敬,有一句特別用語:「真主、格達費、利比亞,其他什麼都不是。」把領導人與真主並論,在穆斯林世界非常罕見,更何況「格達費」排名真主之後,國家之前。在一些虔誠的宗教人士眼中,格達費甚至是一個狂妄的異教徒。的黎波里一場足球賽後,離開賽場的人們曾湧上街頭,拍手高歌「格達費不是穆斯林」。滿眼領導人畫像,看似一個又一個神話,其實無關宗教,強調的是凡人在地上的統治。</p>
<hr>
<p>第 305 頁<br>
比利時攝影師布魯諾告訴同行們,他無意中進入過穆薩新聞團隊辦公室,裡面沒人,辦公桌上攤著格達費畫像,還有寫了一半的遊行標語。同一天下午,新聞部組織記者去市中心廣場採訪示威民眾,布魯諾見過的畫像和標語就出現在那裡。不僅如此,「示威民眾」都是可携式的,可以出現在記者團所到的任何地方。新聞部大巴載著記者去往二百公里外的米蘇拉塔(Misrata), 一輛小型巴士如影隨形,玻璃窗背後是標語、綠旗,乘客正是多名市中心「民眾」,準備出現在米蘇拉塔。中途休息,記者與他們相逢一笑,荒謬到極點,反成娛樂。</p>
<hr>
<p>第 309 頁<br>
獨裁政權特徵之一,是給維護統治的「體制內」人員支付高於體制外民眾的收入,以此維繫忠誠。一旦這種好處喪失,就可能瓦解維護獨裁的體系。看似銅牆鐵壁的舊制,放大看來漏洞百出,崩潰起來也是一朝之事。</p>
<hr>
<p>第 313 頁<br>
利比亞全稱為「大阿拉伯利比亞人民社會主義民眾國」(The Great Socialist People's Libyan Arab Jamahiriya)。「民眾國」(Al-Jamahiriyyah)是格達費上校憑空造出來的一個阿拉伯詞彙,他認為百分之五十一壓倒百分之四十九的民主選舉最不合理,利比亞只能搞全民主政。根據中國社科院西亞非洲所研究員殷罡的考察,全民主政是這樣實施的:全國數千「人民委員會」構成地方管理機構,牽頭人不是選舉産生,而是「推舉」出來的,「遇有不同意見,不能決定時,要深入討論,直至達成一致」。偏偏湊巧的是,「一致達成的意見」,每次都把重要部門歸於格達費的心腹掌控。
二十世紀八〇年代,格達費武力鎮壓班加西起義。一九九六年,阿布·薩利姆監獄抗爭,三小時內一千兩百七十名政治犯被殺。所謂「協商達成一致」,不過是獨裁者「用一批聽話的人民換掉另一批不聽話的人民」而已。
「全民主政」的招牌下,組建政黨會以「叛國罪」論處。沒有政治光譜可以安放異議,民眾的訴求只剩下了擁戴或憎惡格達費統治。於是,推翻格達費的革命, 一上來也成了一群民眾壓倒另一群民眾。</p>
<hr>
<p>第 322 頁<br>
歷史學家認為, 一個國家政治與經濟的運作效率,往往與掌權者在位時間呈反比。體系內若有超越個人的制度,可以減少「時間」的影響,但是如果沒有約束個人或集體長期把持利益的行為,終究會產生負面效應。石油大國利比亞,腐敗指數遠高於非洲鄰國。首都街道坑坑窪窪,統治者無心治理。
真正維繫「卡里斯馬」統治的是什麼呢?秘密警察、武裝鎮壓。有數據說,利比亞百分之十至十五的人負責向政府彙報百姓言行——全民噤聲顯而易見,當政府發言人安排記者到某地採訪,幾次有人在我們耳邊飛快扔下一句「格達費不好」後,即刻走遠。對待反對者,格達費絕不手軟,公開處刑或在電視上直播血淋淋的畫面。另一邊,親格達費派別、部落又往往得到莫大的好處,比如利比亞中部格達費家鄉地區,人們感念政府福利周全,口口聲聲喊效忠上校。「卡里斯馬」有兩隻手, 一隻是神一般的感召,另一隻則是魔一般的恐嚇。
答案也許稍嫌諷刺。突尼西亞與埃及恰恰因為統治者留下一線公共空間,令怒火有管道表達,而不致走火。穆巴拉克統治時期,民眾有權在可控範圍內和平示威。換句話說,透過非暴力手段表達訴求,埃及人並不陌生。
相反,格達費統治下的利比亞,不存在表達公共意見的平台。他對異議者鐵腕鎮壓,反對派銘記的只有「血債血償」。更壞的消息是,世界「理性抗爭」組織統計一九四〇年至二〇〇六年全球暴力及非暴力鬥爭,結果顯示,暴力革命即便成功,五年內達至民主的先例只有百务之五,但百分之四十一的非暴力鬥爭最終過渡到民主政治,而「十年內再爆發內戰的可能」,前者高出一倍。格達費身亡之後,利比亞境內暴力不止,令人擔憂理論成讖。</p>
<hr>
<p>第 332 頁<br>
《後美國時代》(The Post American World)作者法里德·札卡瑞亞(Fareed Zakaria)、在早年另一本書《自由的未來》(The Future of Freedom)中,首先把這種現象稱作「不自由的民主」(illiberal democracy)。真正的民主是個套餐,不僅有顯而易見的選舉,還得有配套的司法獨立、權力監督、言論自由、集會自由、信仰自由、私產保護等等。這些總稱為「自由」(liberty)的護航措施有比較隱蔽的彈性,不像選舉那樣,「有還是沒有」一望便知。
中文裡的「自由」,常讓人想起「無拘無束」,甚至「無法無天」、「隨心所欲」,而札卡瑞亞在這裡講的「自由」恰恰相反,是一套細緻縝密的法律保障。有了這番保障,選票才有價值。可惜的是,札卡瑞亞慨歎,「以選舉為特徵的民主」橫掃全球,「自由」卻還只在西方徘徊。</p>
<hr>
<p>第 346 頁<br>
飛機降落,全體乘客鼓掌,慶賀平安抵達。這似乎是非常西方的習慣。</p>
<hr>
<p>第 349 頁<br>
「看,俄羅斯的源頭。」伊萬指了指廣場中心雕像,拍拍心口,「基輔是俄羅斯的母親。」雕像是傳說中建立基輔的四兄妹,名字首字連在一起拼成「基輔」的拉丁寫法。
古代俄羅斯人的第一個政治活動中心在基輔。十三世紀蒙古入侵,俄羅斯人棄守基輔一路向北。先是 Vladmimir-na-Klaizarn,然後是莫斯科,十八世紀終於落腳在聖彼得堡。
烏克蘭與俄羅斯的歷史,就是歷史學家打架的歷史。在俄羅斯看來,烏克蘭沒有歷史,它是十九世紀德國、奧地利為了削弱俄羅斯搗鼓出來的一個「概念」。可是俄羅斯又把基輔當作自己的「母親」,說自己的祖先是最早在基輔建都的羅斯國王。羅斯統治的地區也叫瓦良格,就是烏克蘭賣給中國那艘航母的名字。</p>
<hr>
<p>第 353 頁<br>
「你要是有孩子,希望他們在哪裡接受教育呢?」「當然是俄羅斯。我們的考試叫考試,美國那種只能叫測驗,太簡單了……聽我說,俄羅斯有油,中國有錢,我們應該聯合起來,西方就不敢這麼橫了。」
「告訴我,到底什麼是俄羅斯的靈魂?」
「就是誰也壓不垮我們,誰也不能叫我們屈服。」
跟伊萬道別後,我邊往地鐵走,邊試圖梳理他的思路:在烏克蘭長大的半個俄羅斯人,對烏克蘭有感情,但歸根結底又把烏克蘭與俄羅斯看作一個共同體:個體的價值,必須依靠強大的共同體去實現。</p>
<hr>
<p>第 354 頁<br>
英雄。民主。自由。獨立。解放。祖國。吃飽穿暖以後,細小的詞語滿足不了我們,而這些宏大的,又面目模糊、含義不清。</p>
<hr>
<p>第 386 頁<br>
邊界初開,東西柏林經歷了巨大的經濟落差。二十年後,西柏林漸漸變為高檔住宅區,東柏林則因為房租低廉,成為整個歐洲年輕藝術家的天堂。東柏林咖啡館的早餐以豐盛和漫長著稱,這裡無人早起,半數人口都是藝術家。藝術家提供不了太多稅收,柏林欠下很多外債,靠借貸發展。柏林圍牆倒下之初,世界為之興奮,跨國企業摩拳擦掌,但是這裡不具備商業城市的氛圍。十五年後,索尼影視中心(Sony Center)黯然出售。西門子盤算了很久,終於也沒有來。</p>
<hr>
<p>第 396 頁<br>
世界驚訝,但並不反感。希特勒完結,柏林圍牆倒塌,德國人不斷道歉和自省——「整個國家從對『強大』的渴求,轉為正常。沒什麼比正常更美好的了。」毛斯巴赫愉快地笑起來。他有一種舉重若輕的天分,在任何極端的集體情緒中,都要努力回到心裡那個平衡點。</p>
<hr>
<p>第 399 頁<br>
德國墨卡托智庫(Mercator Institute for China Studies)統計過歐洲人在 Google 上搜索關於「中國」的熱門詞彙:「長城」、「創新」、「統治世界」、「中國菜」、「吃狗肉」等等,各國不一而足。他們也列出中國網民在百度上想知道的歐洲:「雅思」、「屠猶」、「足球」……但有一個詞是中國人對歐洲各國必搜的,出現頻率非常高:「買什麼便宜」。
二十年前,柏林圍牆西邊的資本主義,理直氣壯用物質去誘惑東邊的人。而今天,在中國人面前,這種誘惑僅僅是為他們的旅途增添「帝王般的享受」。中國護照仍然處處需要簽證,但中國錢包早已全球通用。那晚,在梅克爾發願吃生蠔的凱賓斯基酒店對面,我見到一個中國人。因為言論無忌,他無法回去。世界在中國遊客面前暢通無礙,但祖國本身,有時正是一道牆。</p>
<hr>
<p>第 400 頁<br>
在柏林居住另一個十三年後,她給自己的生活做了個總結,創作成《東西相遇》,用漫畫對照德國人與中國人思維舉止細微處的差異。德國人用眼睛旅行,中國人離不開相機。德國人直面問題,中國人繞道而行。德國人安靜小聲,中國人熱熱鬧鬧。</p>
<hr>
<p>第 402 頁<br>
東西德人本是一家。二戰結束後,德國被蘇聯和西方分而占之, 一九四九年東德、西德分別建國, 一九六一年柏林圍牆豎起。四十年間,兩邊的人變得不再是一個模子裡刻出來的。圍牆倒塌後二十多年,彼此還是立刻能從舉止言談裡辨認出差異。這是何等的驚人和悲哀。</p>
<hr>
<p>第 403 頁<br>
一名同行激動地拉我去看另一塊展板:
(正面寫著:)
德意志民主共和國憲法第二條第一段:「德意志民主共和國所有權力由工人行使。」
(反面)
人民代表在工人階級政黨的領導下,行使工人農民的權力。
(正面)
德意志民主共和國憲法第二十七條第二段:「保障報紙、電台和電視台的自由。」
(反面)
如果新聞傷害社會主義意識形態,它的自由就可能被剝奪。
正面,是堂皇的說詞。反面,是實際發生的事情。</p>
<hr>
<p>第 408 頁<br>
三年前,我在瑞士聽說列支敦斯登準備公投,立刻來了興趣:列國雖小,人可是全世界最富裕的居民——查一下世界銀行、聯合國及美國中情局發佈的資料,列支敦斯登人均國內生產總值(GDP per capital)或人均國民收入,幾乎年年進三甲。二○一二年人均國內生產總值世界第一,是那一年中國的二十三倍。我向來以為,揭竿而起是因為活不下去,這群「天堂裡的人民」怎麼也鬧起來了?</p>
<hr>
<p>第 409 頁<br>
在君主制次第灰飛煙滅的歐洲,列支敦斯登大公百年實權在握,其中一個原因——國是他家買的。四百多年前,列支敦斯登家族買下兩塊直屬德意志神聖羅馬帝國的小莊園,合併為小型公國, 一轉身,地主有了政治身分,頂著大公頭銜翩然坐上帝國議會。今天這個小公國的國名,仍然是列支敦斯登家族姓氏。國民的身分意識,與王室家族不可分割。
二戰後公國也曾拮据困頓。後來,在現任大公的父親弗朗茨·約瑟夫二世(Franz Joseph II)治下,通過比瑞士更低的稅賦,更開放的銀行制度,吸引源源資金,再加上製造業沒有鬆懈, 一躍成為首富。</p>
<hr>
<p>第 409 頁<br>
漢斯·亞當二世的公開形象更接近學者,花白頭髮,西服翩翩,熱衷著書傳播執政理念。列支敦斯登街道上看不見他的畫像,旅遊紀念品上也沒有。從大公的父親開始,列支敦斯登王室就以低調、親民為人稱道。珍妮說,列支敦斯登年輕人出國,最終大多選擇回來,哪裡都不如祖國的福利好。</p>
<hr>
<p>第 412 頁<br>
P 先生曾提到一個細節,令我驚奇。他反大公否決權的立場眾所周知,但作為議會黨派代表,每週進宮面見大公。
「你每星期都見到你反對的人?」
「是的,作為黨派代表,我隨時可以打電話到王宮,要求會面,通常第二、第三天就可以見到大公或他的兒子王儲。」
電影裡進宮面聖的情形浮現腦海,我試著問:「你得下跪嗎?吻手嗎?」面見列支敦斯登大公,一般禮節性地稱呼「殿下」。P 是大公特權的反對者,拒絕行禮。第一次進宮,他問大公:「我的名字是畢伯·佛里克,請問我該如何稱呼您?」「叫我列支敦斯登先生。」大公答道。從此,會面代表中只有他不用口呼「殿下」。 「父母從小教導,別人如何對待你,取決於你是否允許他們那樣做。如果列支敦斯登大公變成獨裁者,那是人民縱容他那樣做。」</p>
<hr>
<p>第 414 頁<br>
「世界上無數人會對你們說,這是最富裕的地方,宛如天堂,還有什麼不滿意?廢除了大公的否決權,你們的明天會更好嗎?」
賈妮往椅子上靠了靠,緩緩說:「廢除否決權,對我們的日常生活沒什麼影響,早晨起來太陽不會更亮。但重要的是,我們不想有個人坐在那裡『允許』改變發生,人民應該自行決定。大公的權力,是我們脖子上的一根繩索。」</p>
<hr>
<p>第 416 頁<br>
通常而言,經濟發展到一定程度,人們會要求更加透明、更多參與感的政治體制,列支敦斯登已經沒有「絕對意義上的窮人」,就連收入相對較低的百分之十人群,都獲得國家補貼,有車有房。P 先生說,粗略一分,百分之六十列支敦斯登國民為中產階級,百分之三十高收入者大多從事金融業。但反對大公否決權的人,很難以收入、年齡、性別劃分,「只是一群思想超群的人」。
然而,這群人太少了。列支敦斯登屢次公投失敗,展現了一種令人困惑的景象:當經濟達到一定水準時,人們對改變上層建築的要求減弱。又如,另一個國民最富裕的國家卡達,實行的是絕對君主制,超然穩定。新加坡有繁榮無自由,也證明了經濟非政治變革的充分條件,甚至不是必要條件。</p>
<hr>
<p>第 416 頁<br>
千百年來,奧地利大地上的王朝公國,此起彼伏,盛極一時,奥匈帝國半個世紀的榮光與傳奇似乎從未遠離,往事沉澱在血液裡,封建意識遊蕩在現代國家的呼吸中。今日實行代議制民主制度的奥地利,早就不見了王室,但人際關係中身分等級依然分明,個體不習慣做決定,遇事第一反應必是「問我的長官」。瑞士建築師在列支敦斯登人身上,同樣看到個體精神的缺乏。</p>
<hr>
<p>第 426 頁<br>
眾院大廳裡,潔西嘉請大家傳閱兩個厚厚的本子。原來每個議員發言的每一句話,都會被記錄下來。這兩本是今年以來的現場紀錄。兩院大廳還安裝了直播攝影鏡頭,記者、公眾都可以同步收看。
我讀不懂本子上的筆記,薩賓娜叫我留意其中不同文字。瑞士有四種官方語言:德語、法語、義大利語和羅曼什語(Romansh)。多民族、多語言的國家很多,瑞士的奇特之處在於,不推廣統一語言,也沒有統一語言可推廣。即便在莊嚴的國會,議員們也是操不同方言,筆錄員飛速切換。現場配同聲傳譯,但議員大多精通兩三種語言,不需要翻譯,雞同鴨講,溝通無礙。當他們宣誓成為議員時,誓詞都是用不同語言念出來的。</p>
<hr>
<p>第 428 頁<br>
國會走廊盡頭是個簡單的辦公室,總統問政處。瑞士總統不是一個人,而是七個人,輪流坐莊,一人當一年總統。七人班子其實是七個部長,各司兩三個部。目前輪值總統是女性,問政處門楣上的「總統」一詞改成陰性。</p>
<hr>
<p>第 430 頁<br>
另外,「直接民主」的原則並非「簡單多數」,而是以「雙重多數」,避免人們做出愚蠢的選擇(比如戰爭),涉及修憲,除了獲得全民多數,還須取得以各州為單位的「州多數」,這一程序賦予公投結果更多理性。
是不是瑞士小國寡民,直接民主才找到合適的土壤?格達費的利比亞人口五百六十萬,少於瑞士的八百萬,也號稱採用直接民主,到頭來卻是獨裁者「溫情脈脈的面紗」。委內瑞拉人的公投,賦予查維斯終身連任權,更像是維護統治的工具。他們的「直接民主」少了瑞士版的兩大基礎:堅定的法律保障、嚴格的程序限定。克里斯·科巴克(Kris W. Kobach)在《公投:瑞士的直接民主》 (The Referendum: Direct Democracy in Switzerland)一書中指出,瑞士以罕見的直接民主,實現了罕見的穩定和富裕,「與其說它是個特例,不如稱之為先鋒」,它的經驗不無可取之處。</p>
<hr>
<p>第 431 頁<br>
瑞士的存在,證明了另一種可能:人民的理性值得信賴,「大一統」的牢靠來自個體的平等與自由,而不是誰要誰犧牲一些權利。</p>
<hr>
<p>第 446 頁<br>
平心而論,劇中英國首相不過具備一般政客都會犯的毛病:野心比能力大,私欲比公益重要。成天囈語要是英國救了歐元,自己就該成為歐盟主席。選舉前做的一切,就是為了上位,上位之後,全部目標就是保位。當局面終於搞砸,哭著喊著要找女王請辭。二號秘書終於看破,冷冷道:「首相,其實您的位子保不住,對百姓並不是壞事。」唐寧街大小人物,都被一根看不見的繩索牽制,那就是民意。一切都是為了取悅民意。媒體或理直氣壯,或死纏爛打,也是因為公眾輿論後盾堅強。</p>
<hr>
<p>第 449 頁<br>
二戰後,殖民地獨立浪潮驚濤掠岸。始於伊莉莎白二世的父親喬治六世,印度、緬甸、斯里蘭卡相繼獨立。伊莉莎白二世初登王位,蘇伊士運河危機爆發,英國棄守埃及,後人多將此視為帝國衰弱的真正信號。一九五七年的馬來西亞,六〇年代的非洲諸國, 一九九四年的南非, 一九九七年的香港。帝國版圖,如沙灘上作畫,終為潮流吞沒,倏忽不見蹤影。</p>
<hr>
<p>第 454 頁<br>
名義上「率土之濱,莫非王臣」,但英國君主三百年來沒有否定過議會做出的決定。普天之下就算還是王土,我花十英鎊進入的下議院,卻是女王終身不可踏足的禁地。導遊說,如果女王膽敢走過來,下院大門將毫不留情地在她面前狠狠關上。下議院英文是「House of Commons」,「平民或庶民之所」。國王的歸國王,庶民的歸庶民。</p>
<hr>
<p>第 456 頁<br>
「君子訥於言而敏於行」。「說話」於我們不算頭等大事。但現實是,很多事情沒有說明,沒有解釋,於是連「行」也變得語焉不詳。</p>
<hr>
<p>第 462 頁<br>
未來全球不穩定因素之一,正是飛速增長的中產階級與落後的管治之間的衝突。
但是這種衝突本身,很難單獨帶來徹底、積極的改變。中產階級革命改變不了什麼。他們通常手無寸鐵,跟傳統勢力缺乏聯繫。</p>
<hr>
<p>第 464 頁<br>
經濟不是催生革命的決定性因素,但是統治者手中如果有經濟這張牌,就可以拖延革命的發生,土耳其、巴林鬧得再凶也無法翻天,列支敦斯登的富裕令大多數人安於現狀。經不起「阿拉伯之春」吹拂的,往往是推行經濟改革的共和體制,而躺在石油上的君主制國家,最多是吹縐春水,卻興不起浪潮。中國向委内瑞拉提供的數百億美金貸款,客觀上令查維斯和他的繼承者兩手不空。</p>
<hr>
<p>第 470 頁<br>
中國人好論成敗,然而成敗最經不起時間考驗。歷史不在意歡呼或鞭撻,它多稜鏡般的顏色、謎一般的命運,期待注視與思考。阿拉伯社會變革始於二〇一〇年末,展示了無窮側面:中產革命缺乏組織,「窮人政黨」與中産對立,選票被曲解為民主政治唯一手段,舊勢力在新變局中的影響,民主轉型中的威權懷舊,威權手段在新變局中的笨拙,先進生產力第一次不為統治者壟斷,民主大門該不該向地下組織敞開,革命神聖感與神聖感的消散,法治缺失民主無以維繫,國際干預的法律模糊地帶……變革中有太多值得探討的話題,值得汲取的教訓。簡單歸於成敗,不知是因為禁忌重重,還是思維惰性?我們關上電視,看完微博上的互罵之後洗洗睡去,很少心平氣和地探尋得失原委。</p>
<hr>
<p>以上摘自:<br>
<img src="https://img1.doubanio.com/view/subject/l/public/s29166267.jpg" alt="《拜訪革命》"><br>
<a href="https://book.douban.com/subject/26919483/">《拜訪革命》</a><br>
副标题: 從加德滿都、德黑蘭到倫敦,全球民主浪潮的見證 <br>
作者: 周軼君 <br>
出版社: 八旗文化 <br>
ISBN: 9789869384421</p>
使用SCP命令转移Linux文件
https://acuario.xyz/posts/how-to-use-scp-cmd-to-transfer-linux-file/
2023-09-27T18:25:39+00:00
2018-05-30T20:51:46+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="前言">前言</h2>
<p>出于更换 VPS 的目的,不得不对文件进行转移。最原始的办法可能是从 <code>A</code> 服务器拷贝一份到<code>本机</code>,然后再重新上传到 <code>B</code> 服务器。这样做既繁琐又费时。不如使用 Linux 的 <code>scp</code> 命令进行快速转移来的方便。</p>……
<h2 id="前言">前言</h2>
<p>出于更换 VPS 的目的,不得不对文件进行转移。最原始的办法可能是从 <code>A</code> 服务器拷贝一份到<code>本机</code>,然后再重新上传到 <code>B</code> 服务器。这样做既繁琐又费时。不如使用 Linux 的 <code>scp</code> 命令进行快速转移来的方便。</p>
<h2 id="简介">简介</h2>
<p><code>scp</code>(secure copy),可以用于在 Linux 下进行远程文件拷贝。类似于 <code>cp</code> 命令,<code>scp</code> 是应用于多设备间的传输拷贝,而前者是 Linux 本地命令。另外,<code>scp</code> 为 SSH 加密传输,安全性有保障——也因此,连接的端口为远端服务器的 SSH 服务端口(SSH 一般默认端口为 22)。</p>
<h2 id="命令格式">命令格式</h2>
<pre tabindex="0"><code>scp -参数 [[user@]host1:]file1 ... [[user@]host2:]file2
</code></pre><h2 id="常用命令参数">常用命令参数</h2>
<table>
<thead>
<tr>
<th>参数</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>-P</td>
<td>SSH 端口,缺省值为 22</td>
</tr>
<tr>
<td>-i</td>
<td>SSH 密钥登录,后面一个参数为私钥地址</td>
</tr>
<tr>
<td>-l</td>
<td>带宽限制,单位 Kbps</td>
</tr>
<tr>
<td>-r</td>
<td>递归复制整个目录</td>
</tr>
<tr>
<td>-C</td>
<td>允许压缩</td>
</tr>
</tbody>
</table>
<h2 id="常用命令">常用命令</h2>
<p>以下命令假设已登录<strong>本地机器</strong>为 <code>A</code>(IP: 192.168.1.1),<strong>远端机器</strong>为 <code>B</code>(IP: 192.168.2.1)
根据 SSH 登录方式和 SSH 端口的不同,拷贝命令分为以下两种:</p>
<ol>
<li>
<p>远端 <code>B</code> 为密码登录, SSH 为默认端口 22
<code>A:/abc/</code> >>>上传>>> <code>B:/root</code> :</p>
<pre tabindex="0"><code>scp -r /abc root@192.168.2.1:/root
</code></pre><p><code>A:/root</code> <<<下载<<< <code>B:/abc/</code> :</p>
<pre tabindex="0"><code>scp -r root@192.168.2.1:/abc /root
</code></pre></li>
<li>
<p>远端 <code>B</code> 为密钥(密钥文件为 <code>.ssh/id_rsa</code>)登录, SSH 端口为 2222
<code>A:/abc/</code> >>>上传>>> <code>B:/root</code> :</p>
<pre tabindex="0"><code>scp -P 2222 -i .ssh/id_rsa -r /abc root@192.168.2.1:/root
</code></pre><p><code>A:/root</code> <<<下载<<< <code>B:/abc/</code> :</p>
<pre tabindex="0"><code>scp -P 2222 -i .ssh/id_rsa -r root@192.168.2.1:/abc /root
</code></pre><p>p.s. 使用密钥进行 <code>scp</code> 时,需保证密钥文件 <code>.ssh/id_rsa</code> 对应的公钥 <code>.ssh/id_rsa.pub</code> 内容已经写入到 <code>B</code> 的 <code>/root/.sshauthorized_keys</code> 文件中,否则无法正常使用密钥登录。具体原因与 SSH 密钥登录一致。</p>
</li>
</ol>
<hr>
<p>参考链接:
<a href="http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/scp.html">scp 跨机远程拷贝</a></p>
《以你的名字呼唤我》读书笔记
https://acuario.xyz/others/call-me-by-your-name-clip/
2023-09-27T18:25:39+00:00
2018-05-27T17:03:15+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p><img src="https://i.loli.net/2018/05/27/5b0a77b895b93.png" alt="Call Me by Your Name"></p>
<h2 id="以你的名字呼唤我">以你的名字呼唤我</h2>
<blockquote>
<p>三四十年后,我将回到这里,回想起我永志不忘的这段对话,也有可能有一天我会想忘掉。我将与我的妻儿来到这儿,叫他们看这片风景,指着海湾、咖啡馆、“跃动舞厅”、“大饭店”,站在这里让那些雕像、草背椅和摇摇欲坠的木桌帮我回忆起曾有那么一个人名叫奥利弗。</p>
</blockquote>……
<p><img src="https://i.loli.net/2018/05/27/5b0a77b895b93.png" alt="Call Me by Your Name"></p>
<h2 id="以你的名字呼唤我">以你的名字呼唤我</h2>
<blockquote>
<p>三四十年后,我将回到这里,回想起我永志不忘的这段对话,也有可能有一天我会想忘掉。我将与我的妻儿来到这儿,叫他们看这片风景,指着海湾、咖啡馆、“跃动舞厅”、“大饭店”,站在这里让那些雕像、草背椅和摇摇欲坠的木桌帮我回忆起曾有那么一个人名叫奥利弗。</p>
</blockquote>
<p>不得不说,在我看完《Call Me By You Name》的电影之后,我感到一丝丝遗憾和失落。不仅仅因为 Elio 和 Oliver 间那一段没有结果的感情,更因为影片无力于表达 Elio 丰富细腻的情感与心境。</p>
<p>我知道我知道,安德列 · 艾席蒙(即原著作者)作为编剧参与了电影的改编,但是电影镜头的表达依旧失去了 Elio 最令我着迷的内心戏。如果我没有看过原著,那么我对这部电影的评价一定是平庸而肤浅的,对此我深信不疑——因为 Elio 和 Oliver 的感情是如此波澜不惊,他们之间发生的一点一滴,不过是某人和某人的日常罢:</p>
<blockquote>
<p>-大家都在这里做些什么?<br>
-不做什么。等夏天结束。<br>
-那么,冬天做什么?<br>
-先别告诉我:是等夏天来,对不对?</p>
</blockquote>
<p>无论答案是什么,Oliver 其实都已看到 Elio 的内心,因为这之后的几个星期生发的情愫,会让 Elio 在这之后的多少个夏天想起这个夏天,想起曾属于自己并一直属于自己的卧室,想起被共享的属于自己的秘密基地,想起<a href="https://weibo.com/ttarticle/p/show?id=2309404158040470334211">圣格来孟症候群</a>,想起红色、黄色、蓝色和绿色,想起植物王国的桃子,想起那个以自己名字呼唤的人。</p>
<blockquote>
<p>这话听起来有点像我几星期前第一次听到的 <em><strong>Later</strong></em>——尖锐、直率,阴郁沉闷,语调平板,没有一点我们刚刚共享的喜悦或热情。</p>
</blockquote>
<p>不可否认的是,害怕听到那句 <em>Later</em> 的不仅仅是观影者,更是 Elio 自己。因为这是来自 Oliver 的咒语和审判词——对二者间不可继续的对话不加注解地画上句点,对二者间不可继续的感情写下的休止符。无论 Elio 对李斯特的风格多么谙熟于心,无论 Elio 如何熟稔地用巴赫的风格去改写这首恋爱的变奏曲,最终获得的也仅是这满心期待的诗歌和乐章的未完成稿。</p>
<p>但,这已足够为内心的悸动做深刻的证明,足够为以名字呼唤的意乱情迷写下序章,足够向他展示自己的蛛丝马迹:</p>
<blockquote>
<p>我完全没想到要带他到这儿来。不只是为了向他展示我的小世界,也是为了请求我的小世界接受他,让我这个夏日午后独处的小基地也能认识他,评断他,看他适不适合这里,接纳他,以便我能回到这里来缅怀。我到这儿来逃离已知的世界,寻找我自己虚构的另一个世界。我向他引介我的起点。只要列出我在这儿读过的作品,他就知道我游历的蛛丝马迹。</p>
</blockquote>
<hr>
<h2 id="如果这都不算表白">如果这都不算表白</h2>
<blockquote>
<p>「有什么是你不知道的?」<br>
我看着他。机会来了。把握、或失去这个机会,但无论如何,我知道我永远无法摆脱这种耻辱;或者洋洋得意接受他的恭维,却对其他一切感到后悔。这或许是我这辈子第一次在毫无准备的状况下对成年人说话。我太紧张,以致无法做任何准备。<br>
「我什么都不知道,奥利佛。不知道,什么都不知道。」<br>
「你比这儿任何人知道的都多。」<br>
为什么他要用乏味的信心喊话回应我近乎悲惨的语调?<br>
「但愿你知道,我对眞正重要的事有多么无知。」<br>
我拔足涉水,想办法既不溺水、也不安全游过,只是留在当场,因为这里就是眞相所在的位置——尽管我无法吐实,甚至给予暗示,但我发誓眞相就在我们身边,就像我们聊起刚刚游泳时搞丢的项链那样:我知道项链就在水里。但愿他知道,但愿他知道我给他每个机会,将二和二加在一起,然后得出比无限还大的数字。<br>
如果他明了,他必定早已起疑:如果他起疑,他必定曾经处于相同的立场,从平行小路的另一头,以冰冷、带着敌意、玻璃眼般犀利且无所不知的眼光观察我。<br>
他必定想到什么——天晓得是什么。或许他不想露出太惊讶的神色。<br>
「什么重要的事?」<br>
他不老实吗?<br>
「你明明知道。到了这节骨眼,就属<strong>你</strong>最该知道。」<br>
沉默。<br>
「你为什么要告诉我这一切?」<br>
「因为我认为你该知道。」<br>
「因为你认为我该知道。」他慢慢复述我的话,试着了解这几个字的完整意义,理出头绪,借着重复这句话拖延时间。我知道,铁烧得正灼热。<br>
我脱口而出:「因为我希望你知道。因为除了你之外,我没有别人可说。」<br>
就这样,我说出来了。<br>
我说的够清楚吗?<br>
我正要岔开话题,讲点海或明天的天气,聊聊父亲每年此时总是承诺要驾船去 E 城,眞不知是否可行。<br>
但是多亏他,他不肯放过我。<br>
「你知道你说了什么吗?」<br>
这次我望着海,用含混疲倦的声调说。这是我最后的迂回、最后的掩蔽、最后的逃脱。 「知道,我知道我说什么,你<strong>一点</strong>也没误会。我只是不太擅长说话。不过你大可不再跟我说话。」<br>
「等等。我没有误解你的话吗?」<br>
「<strong>没有</strong>。」既然秘密已经脱口,我大可摆出从容不迫、略为恼怒的态度,就像屈服于警方的重罪犯,向一个个警察,一而再、再而三坦承自己如何抢劫店家。<br>
「在这里等我,我得上楼去拿些文件。别走开。」<br>
我用信任的微笑看着他「你很清楚我不会走开。」<br>
如果这不算再次表白,那什么才算?</p>
</blockquote>
<hr>
<h2 id="我不羡慕痛苦本身但我羡慕你会痛">我不羡慕痛苦本身,但我羡慕你会痛</h2>
<p>令我遗憾的,还有那一幕 Elio 的 ASMR,电影的草草带过多半误导了太多的观众,让人以为这是因为 Elio 在一遍遍回想自己与 Oliver 释放荷尔蒙的欢愉。但恰恰相反,这正是现实上演的一出喜剧:</p>
<blockquote>
<p>或许是我的脚迷了路碰到他的。它撤退,不是马上,却也够快了,仿佛刻意留一段恰切的等待空当,好避免留下惊慌退缩的印象。我也多等了几秒,从没细想,只是让自己的脚开始搜寻另一只脚。才开始找,脚趾就碰到了他的脚;他的脚几乎动也不动,像一艘海盗船,尽管制造各种假象表示自己已经逃到数里之外,实际上却隐藏在距离仅五十码的浓雾中,一等机会出现就要突袭。我的脚还来不及采取任何行动,毫无预警,没给我任何时间接近他的脚或再度退回到安全距离之外休息,他突然温柔轻缓地伸脚压在我的脚上,开始爱抚摩擦,没有停歇。光滑圆润的脚踵顶着我的脚背,偶尔重重压上来,旋即放轻,以脚趾一阵爱抚,从头到尾暗示这是抱着好玩和游戏的心情做的。他以这种方式来冷落坐在我们对面从事“正餐苦差”那些人,也告诉我这件事与其他人无关,彻底仅限于我们之间,这是我们的事。但我不该做多余的解读,他鬼祟、顽强的爱抚让我背脊发凉,令我头昏目眩。不,我不会哭,这不是恐慌发作,这不是“意乱情迷”,我也不打算穿着短裤达到高潮,虽然我非常、非常喜欢,尤其他以足弓叠在我脚上的时刻。我盯着面前的沙拉盘,看见点缀着果汁的巧克力蛋糕上似乎有人倒人了比平常多的番茄酱汁,而且愈来愈多,那酱汁似乎来自我头上的天花板,直到我醒悟那是从我的鼻子大量涌出的。我倒吸一口气,立刻捏起餐巾往鼻子上捂,尽可能把头往后仰。“冰块,玛法尔达,拜托,快!”我轻轻说,表现出一切都在掌握中的样子。我向客人道歉:“今天早上我去了山上。常有的事。”</p>
</blockquote>
<p>我们和 Elio 一样,无法知道其父的生命经历,但我们也许可以获得启迪:</p>
<blockquote>
<p>我们的心、灵和身体是绝无仅有的。许多人活得好像自己有两个人生可活,一个是模型,另一个是成品,甚至有介于两者之间的各种版本。但我们的心和身体只被给予这一次,而在你终于领悟之前,你的心会疲惫,至于你的身体,总有一天没有人要再看它,更没有人愿意接近。现在的我觉得很遗憾。<strong>我不羡慕痛苦本身。但我羡慕你会痛。你可能感到难过,痛苦。别让它消失,更别说那些有过的快乐</strong>。</p>
</blockquote>
<div class="aplayer" data-id="516358164" data-server="netease" data-type="song" data-mode="single" data-autoplay="true"></div>
Nginx配置反向代理隐藏服务端口
https://acuario.xyz/posts/how-to-use-reverse-proxy-to-hide-server-port/
2023-09-27T18:25:39+00:00
2018-05-17T23:16:42+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="前言">前言</h2>
<p>对于个人开发者来说,在一台 Linux 服务器或自己的 VPS 上,通常会部署多个 Web 服务,有的服务默认监听的是 80/443 端口,只需对 Nginx 进行简单的配置、设置伪静态等等即可完成,而有的服务既非静态网页,也不使用 Linux 中既有的 PHP 等程序,而是使用自己项目内部构建的程序(比如 Node.js、Tomcat 等),这些服务往往监听的是非 80/443 端口,在配置个人域名后,不得不在域名后加上服务器端口才能访问,既不美观,也不方便。是否有办法可以隐藏 URL 中的服务器端口,使用域名进行区分?</p>……
<h2 id="前言">前言</h2>
<p>对于个人开发者来说,在一台 Linux 服务器或自己的 VPS 上,通常会部署多个 Web 服务,有的服务默认监听的是 80/443 端口,只需对 Nginx 进行简单的配置、设置伪静态等等即可完成,而有的服务既非静态网页,也不使用 Linux 中既有的 PHP 等程序,而是使用自己项目内部构建的程序(比如 Node.js、Tomcat 等),这些服务往往监听的是非 80/443 端口,在配置个人域名后,不得不在域名后加上服务器端口才能访问,既不美观,也不方便。是否有办法可以隐藏 URL 中的服务器端口,使用域名进行区分?</p>
<p>例如:
http://1.1.1.1:1111 -> <a href="http://1.example.com">http://1.example.com</a>
http://1.1.1.1:2222 -> <a href="http://2.example.com">http://2.example.com</a>
<a href="http://example.com:3333">http://example.com:3333</a> -> <a href="http://3.example.com">http://3.example.com</a></p>
<h2 id="代理服务器的类型">代理服务器的类型</h2>
<p>与代理服务器相关的概念,主要有正向代理、反向代理、透明代理。这三者的关系在<a href="http://blog.51cto.com/z00w00/1031287">这篇文章</a>里介绍的很清楚,在此言简意赅地做举例梳理:
假设有<code>客户端 A</code>、<code>代理服务器 B</code>、<code>Web 服务器 C</code>:</p>
<ul>
<li>
<p><strong>正向代理</strong>:<code>客户端 A</code> 向 <code>代理服务器 B</code> 发送一个请求并指定 <code>Web 服务器 C</code> 为目标,<code>代理服务器 B</code> 转交请求并将获得的内容返回给 <code>客户端 A</code>。主要实践是突破网络封锁的各类工具。</p>
</li>
<li>
<p><strong><a href="https://zh.wikipedia.org/wiki/%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86">反向代理</a></strong>:<code>客户端 A</code> 类似于 Web 服务器,发出的内容和请求将由 <code>代理服务器 B</code> 进行判断分发,<code>客户端 A</code> 不知道 <code>代理服务器 B</code> 的存在。主要实践是 WEB 服务。</p>
</li>
<li>
<p><strong>透明代理</strong>:<code>客户端 A</code> 不知道 <code>代理服务器 B</code> 的存在,在访问 <code>服务器 C</code> 时,由 <code>代理服务器 B</code> 代为访问,但 <code>代理服务器 B</code> 对报文进行改写和过滤。主要实践是公司内部的网络管理系统(如深某服)。</p>
</li>
</ul>
<h2 id="反向代理的意义">反向代理的意义</h2>
<ol>
<li>如前言所述,把不同的子域名转发到同一机器的不同的服务上。</li>
<li>进一步地,把不同的请求转发到不同的服务器上——即负载均衡。</li>
<li>隐藏实际服务,提升安全性</li>
</ol>
<h2 id="配置-nginx-反向代理">配置 Nginx 反向代理</h2>
<p>实际上对前沿所述的情况,针对某个服务进行 Nginx 反向代理配置很简单,下面是监听域名 example.com 并转发到 8080 端口的例子:</p>
<pre tabindex="0"><code>server {
listen 80;
server_name example.com;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://127.0.0.1:8080/;
}
}
</code></pre><p>在<a href="https://www.jianshu.com/p/2e0fe505766b">另外一篇文章</a>中,我看到了如下示例:</p>
<pre tabindex="0"><code>upstream webServer01 {
server 127.0.0.1:3001;
keepalive 64;
}
upstream webServer02 {
server 127.0.0.1:3002;
keepalive 64;
}
server {
listen 80;
server_name www.myApp01.com;
#access_log /var/log/nginx/test.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Nginx-Proxy true;
proxy_set_header Connection "";
proxy_pass http://webServer01;
}
}
server {
listen 80;
server_name www.myApp02.com;
#access_log /var/log/nginx/test.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Nginx-Proxy true;
proxy_set_header Connection "";
proxy_pass http://webServer02;
}
}
</code></pre><p>这一配置也能实现以 <code>www.myApp01.com</code> 访问时,将进入<code>webServer01</code>,当我们以 <code>www.myApp02.com</code> 访问时,将进入<code>webServer02</code>。其中已经用到的 <code>upstream</code> 模块就是用来配置负载均衡的。关于负载均衡的详细资料,可以参考<a href="http://tengine.taobao.org/book/chapter_05.html">Nginx 开发从入门到精通</a></p>
<h2 id="宝塔面板配置">宝塔面板配置</h2>
<p>如果使用了<a href="https://www.bt.cn/">宝塔面板</a>进行建站,可以在面板菜单【网站】中对特定网站进行设置,转发 1200 端口的例子如下图:</p>
<p><img src="https://i.loli.net/2018/05/17/5afd9bba06413.png" alt="宝塔面板配置网站反向代理"></p>
<hr>
<p>参考链接:
<a href="http://blog.51cto.com/z00w00/1031287">图解正向代理、反向代理、透明代理</a>
<a href="https://www.jianshu.com/p/2e0fe505766b">Nginx 反向代理的一次使用总结</a>
<a href="http://tengine.taobao.org/book/chapter_05.html">Nginx 开发从入门到精通</a></p>
《回锅肉和香菇菜心的语言等级》读书笔记
https://acuario.xyz/others/language-level-of-pork-mushrooms-and-cabbage-clip/
2023-09-27T18:25:39+00:00
2018-05-04T17:36:07+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>第 4 页
以北京的地名来论,老北京口中,以前北京内城的九大门:正阳门、崇文门、宣武门、东直门、朝阳门、西直门、阜成门、德胜门、安定门和皇宫里的天安门、午门、前门,都是不能加“儿”的,一来这些门体量颇大,高耸巍峨;二来,它们还常常跟皇权神权紧密相关,是高高在上万民敬仰的所在,断没有皇上说:“来呀——把这乱臣贼子拖出午门儿斩首!”那也太不严肃了。相反,东便门、西便门则常常在口语里听到儿化。这就是隐藏在语言背后的文化秩序。如今北京城的大门拆得所剩无几,外地人又如何分得出哪门大哪门小?也就越说越乱了,不讨再乱地没人说天安门儿。</p>
<hr>
<p>第 6 页
中国人对于数字的概念,从个、十、百、千数到万跟亿,最多到兆,再往上一般人不大知道还有京、垓、秭、穰、沟、涧、正、载、极……那么大,生活中也的确用不上。但无论怎么大,递进规律是一样的,早在东汉,《数述记遗》一书中就有记载,万万为亿、万亿为兆、万兆为京……所以按照中文的计数方式,若是四位一隔,立时眉目清楚。</p>……
<p>第 4 页
以北京的地名来论,老北京口中,以前北京内城的九大门:正阳门、崇文门、宣武门、东直门、朝阳门、西直门、阜成门、德胜门、安定门和皇宫里的天安门、午门、前门,都是不能加“儿”的,一来这些门体量颇大,高耸巍峨;二来,它们还常常跟皇权神权紧密相关,是高高在上万民敬仰的所在,断没有皇上说:“来呀——把这乱臣贼子拖出午门儿斩首!”那也太不严肃了。相反,东便门、西便门则常常在口语里听到儿化。这就是隐藏在语言背后的文化秩序。如今北京城的大门拆得所剩无几,外地人又如何分得出哪门大哪门小?也就越说越乱了,不讨再乱地没人说天安门儿。</p>
<hr>
<p>第 6 页
中国人对于数字的概念,从个、十、百、千数到万跟亿,最多到兆,再往上一般人不大知道还有京、垓、秭、穰、沟、涧、正、载、极……那么大,生活中也的确用不上。但无论怎么大,递进规律是一样的,早在东汉,《数述记遗》一书中就有记载,万万为亿、万亿为兆、万兆为京……所以按照中文的计数方式,若是四位一隔,立时眉目清楚。</p>
<hr>
<p>第 11 页
在广州,番字两读,“几番痴心”读同“翻”,在地名番禺里却要读作“潘”。一般人觉得这就是个多音字,而语言学家从类似线索里,则发现了语言演变的规律。这就是清代大学问家钱大昕总结出的“古无轻唇音”。这条关于汉语声母演变的重要规律,说通俗点,就是上古汉语里,只有双唇触碰在一起发音的b、p、m;没有把牙齿放在下唇上发音的 f。唇齿音 f 是唐宋以后才慢慢发展演变出来的。只是后来社会在变,语言也在变,一部分双唇音分化出了唇齿音,“番”字就在变化之列,改朝换代时节,日常口语“三番两次”随波逐流,牙齿轻巧地往前探,声母成了 f。至于“番茄”、“番薯”、“番枧”,都是明清以后才从海外传入中华的东西,那时大势已定,自然也读如“翻”。但地名因为跟特定的山川、河流、区域相对应,在本地是经常挂在嘴边的,为了交际的方便,读音字形需要相对稳定,以免造成误解含混。作为在战国时候就出现了的地名“番禺”,于是成了思想保守、行动迟缓的遗老遗少,顽固地双唇一抿,保留了两千年前的古音。
上海开埠晚,很多马路的命名来自别处的地名。就拿番禺路来说,一公里多长,北起延安西路,南至虹桥路,早年初建时以美国城市命名为哥伦比亚路,1943 年改名番禺路,沿用至今。不少民国政要,比如胡汉民、叶公超、古应芬、叶恭绰都是广东番禺人,就算当初改名没有攀附权贵的意思,至少也沾民国望人的光。早年大家比较了解番禺二字的由来,也颇知道正音如何读。前几年还有老人家写信到报社提意见,投诉上海的 72 路公共汽车电子报站读了别字,把番禺路读成了“翻禺路”。风流云转世事变迁,在如今上海人的知识谱系里,番禺二字就只是延安西路附近的一条马路而已,甚至不知它是广州下辖的一个区,自然将番禺之番,等同于番茄之番。我接触到的上海本地人或者上海新移民,十有八九根本觉得说 fan 禺路天经地义。</p>
<hr>
<p>第 16 页
台湾国语会编订过《国音标准汇编》,作为推行标准国语的根据。1946 年起,“老北京”齐铁恨先生每天早晨七点,准时在电台担任“国语读音示范”,播讲当时的各种国语读本,匡正语音。说齐老先生“一言九鼎”也不为过,当时几乎全台湾的国语教师都是就着广播现听现学现卖的,这位国语运动老专家的“京片子”于是就成了台湾国语的活标准,他嘴里的连词“和”读“汗”也就深入人心街知巷闻。齐铁恨是老舍的好友,当年老舍写成名作《骆驼祥子》之前,曾经写信给他打听过骆驼的生活习性,因为齐是北京香山人,山下有许多人家养骆驼。九十年代老舍的儿子舒乙访问台湾,除了觉得“乡音灌耳”,也很好奇台湾人把连词“和”念成“汗”。当时台湾作家何欣解释说:“这是齐铁恨先生在电台上教的,他的话就是法律,怎么教就怎么说了。”舒乙大笑,说:“齐先生使劲使过分了。”舒乙有此一说,大抵因为在北京土语里,连词“和”读 han 原本是轻声,齐老先生上电台郑重其事字正腔圆,一来二去,读得重变成了四声的“汗”。以至于 1949 年以后台湾出的几本正音字典,都标成了 han。这可让纯正北京口音的舒乙,微微觉得,有点汗。</p>
<hr>
<p>第 23 页
事实上,粤语跟普通话,或者粤语跟闽语之间的语言距离,甚至是大过欧洲同一语系之下的两种语言的。比如一个西班牙人和一个葡萄牙人,可以自说自话,但这几乎不妨碍他俩聊天儿。而一个只懂粤语的人和一个只懂闽语的人,却完全是鸡同鸭讲。这也是为什么大多数西方语言学家坚持认为,汉语不是一种单一的语言,而是一组有亲属关系的语言(包括了粤语、闽语、吴语、赣语、湘语、客家话和北方官话)组成的庞大语族。不借助民族共同语“普通话”,大部分的汉语方言都无法互通。但事情的另一面是,可以聊天儿的西班牙人和葡萄牙人,看不懂彼此的报纸,完全听不懂对方说什么的广东人和福建人,却可以笔谈。这也是国内的语言学家坚持粤、闽、吴、赣语等等是汉语方言的重要原因。神奇的汉字,打通古今连接南北,这一点,又是使用拼音文字的欧洲人很难理解的。</p>
<hr>
<p>第 24 页
一直以来坊间流传着一种说法,认为 Mandarin 源于中文的“满大人”。说是以前外国人把满清官员叫作“满大人”,随之他们说的话也就成了 Mandarin,听上去似乎挺靠谱儿的。清末积贫积弱,洋人一攻进来,满大人纷纷丢盔弃甲,加上割地赔款的不堪往事,很多人也就嫌弃了这个词,不愿意它代表咱音韵铿锵的普通话。事实上,这还真是冤枉了 Mandarin。
据利玛窦考证说,这个词最早来源于梵文,意思是会思考的人。后来从梵文发展到印地文,流传到马来文中,又进入了葡萄牙文成为 Mandarin。不管这么曲折的路线是不是十分可靠,但从明朝起西方人便称呼中国官员甚至亚洲国家官员为 Mandarin 了,那个时候还完全没有“满大人”呢。
明朝及清朝中叶之前中国的官方标准语一直是南京话。清初名义上的国语是满语,怎奈汉文化力量强大,进了北京城的八旗子弟都渐渐改了口音,谁也敌不过这时代潮流。于是,雍正八年清政府设置了正音馆,推广以北京音为标准的官话——官员在庙堂上说的话,这就是今天普通话的前身。当年开科取士,写八股文倒是没什么,大家读的都是“四书五经”,用的都是汉字,但一开口,没有官话,皇上如何听得懂福建老臣说话?即便不做京官,清代规定地方上从督抚直至州县一级的各路官员,都不能在自己家乡所属的省、府、州、县内担任要职。跨省做官,也没见过县太爷升堂时还带个师爷翻详的。
也就是在雍正年间,英国人开始把朝廷推行的“官话”翻译成了 Mandarin。同一词根,英语里还有 mandate(政府权力、命令)、mandary(官方的、行政的)等等。用 Mandarin 正是取其“行政推广的语言”之意。这个词有三百多年的历史了,也正是它在英文世界接受程府比较高的原因。</p>
<hr>
<p>第 34 页
不过,在美国,虽然有 94% 的美国人说英语,却只有 31 个州将英语确立为官方语言,不久前还有国会议员提出议案,要求美国政府所有的官方活动都使用英语,为移民规划设立统一的语言标准。在美国国家层面上,英语至今都根本没有政府官方工作语言的法定地位,好玩儿吧?</p>
<hr>
<p>第 47 页
因为有强烈的北京口语色彩,“俩”颇得人心,常常被人拿来转京腔,于是用错的例子比比皆是。有些人错在望文生义,觉得有个人字边,写到人的时候就用它以示郑重。其实根本不关人事。北京话里有个熟语叫仨瓜俩枣,指的就是不值钱的小物件。正因为“俩”原本就隐含了量词,说“俩个人”变得叠床架屋。“小两口”也一样,已经有了量词“口”,当然就不能再用“俩”了。
有一次碰到编辑和校对争执,有篇文章的开头写着:我有俩姥爷。原本是个挺有悬念和情节感的开头,显然要随之铺陈的是关于姥姥的曲折人生。谁知道在校对那里,竟然被改成了“我有姥爷俩”。“俩”字乾坤大挪移,放在了姥爷后面,让人啼笑皆非。校对丝毫不觉得错,振振有词地拿出夫妻俩、姊妹俩、妯娌俩做例子——亲戚关系不都是把“俩”放在后面么?乍一听,还真被他唬住了。仔细分析,的确“俩”既可以出现在名词之前,也可以出现在名词之后。但放在名词后面的“俩”,限制要大得多,根本不能自由滑动。
放在后面的“俩”,要求前面的名词则必须是关系词,而非身份词。比如夫妻、妯娌、姊妹、师徒,都是由关系双方并列成词,二者缺一不可,后面加“俩”,恰好是强调了这种关系必须两个人都在才能成立。而姥爷是种身份,只要闺女生了孩子,某个人就会立即升舱做姥爷,即便外孙不在眼前,也不影响他姥爷的身份。至于表面看上去的反例哥俩、姐俩、娘俩、爷俩,在北京话口语里,中间都是要加“儿”的。它们指称的仍然是兄弟、姐妹、母子(母女),父子(父女)关系。</p>
<hr>
<p>第 57 页
语言学家经过大量的调查实例发现,人们倾向于用较高的抽象度去编码和传播内群体的积极行为和外群体的消极行为,反之亦然。
这话有点高深?把它翻译得通俗点就是,人在说自己人好事和外人坏事的时候,习惯抽象性拔高。韩老师说起焦刘洋用到了“红色中国”和“伟大时刻”,说起破纪录的美国人则很客观地描述着她的成绩和赛前承诺。中国选手失手的时候,韩老师及其他解说员都决计不会说这是“中国的失败”。从认知的角度来看,人不管属于什么群体,是好事还是坏事,总是倾向于用抽象的语言区描述符合自己期待的行为,比如西方世界通常觉得犹太人吝啬,于是任何犹太人有吝啬意味的行为,都会被抽象为犹太人的民族特性,而遇到一个犹太人慷慨解囊,由于不符合人们的预期,行为就被认为是突发的、非典型的,描述的语言就会具体起来。觉得这例子有点远?回忆一下你是怎么描述自家的聪明儿子和陌生的河南人的。偏见其实无所不在。</p>
<hr>
<p>第 63 页
在语言当中。汉语中有不少词汇来自外语,从早前的印度、波斯到后来的日本和西洋各国。外来词恰恰反映了汉语跟异文化交流的轨迹。早年留洋的人是把所有的外来词都音译成汉字的,比如来自梵语的“摩诃般涅槃那”,来自英语的“烟士披里纯”和来自希腊语的“奥林匹克”。问题是这些词音节实在太多了。古汉语以单音节词汇为主,发展到现代汉语,扩展成双音节词汇为主,但始终倾向组成词的每个字都有意义。名词很少长过三音节,四字格成语通常是用来描摹性状而非称呼事物。在汉语中生根发芽的外来词,比如“沙发”、“咖啡”什么的,绝大多数都是双音节,那些单个字没意义且还特别冗长的外来词可就命途多舛了:“摩诃般涅槃那”被斩首剁脚,只剩了“涅槃”;不知所云的“烟士披里纯”被清理门户,改用家生子“灵感”;至于那全球瞩目的运动会,也不得不简缩开支成了“奥运会”,只有开幕式上白岩松特别富有激情的解说,才会一字不漏地说“奥林匹克”。</p>
<hr>
<p>第 68 页
石头剪子布的游戏如今遍布全中国,几乎所有的孩子小时候都玩儿过。普及性这么高的东西,各地叫法却五花八门,北京人叫“cei丁壳”,上海人叫“猜咚猜”,成都人叫“实拳儿”,西安人叫“猜咚吃”,天津叫“笨桥裹”,长春人叫“钢浪锤”,杭州人叫“琴棕绷”,广州人叫“包剪揼”。相比之下,出现在汉代的“手势令”发展到今天,在各地方言中无非叫“猜拳”、“划拳”或者“豁拳”,花样并不很多。二者叫法的巨大反差恰恰说明了,石头剪子布的出现很可能要晚得多,没准儿都是明代以后的事儿。之所以找不到比较准确的记录,多半是因为文人觉得那是无聊童戏,不屑记之。编纂词条的人好古之心可以理解,但追溯到汉代,未免牵强附会。</p>
<hr>
<p>第 78 页
美国语言学家曾经提出过“萨丕尔一沃尔夫假说”,他们倾向认为人类所有较高层次的思维都依赖于语言,人们习惯使用的语言的结构影响人们理解周围环境的方式。这一观点后来被称为语言相对论或者语言决定论。不过好在,语言只是赋予了思维以具体的外壳,这个世界上,既有持相同语言的人彼此的误解,也有持不同语言的人可能的沟通。世界的边界,远比语言大得多。</p>
<hr>
<p>第 79 页
<strong>柬埔寨的译法</strong>
最近因为中国人民的伟大朋友过世,柬埔寨一时成为话题热点。就有人奇怪,柬埔寨三个字跟英文的 Cambodia 相比,除了中间的 “埔” 字约莫有点 bo 的样子,前后的 “柬” 和“寨”,似乎相去甚远。虽说两种语言间的音译,很难百分百准确,但这口音也太重了点吧?
这事还得话说从前。这个中南半岛的古国有两千多年的历史。柬埔寨如今的国名,按照高棉语的读音转写成拉丁拼法是 Kumpuchea,这个名字据说源自他们的建国元勋印度婆罗门僧侣 Kumpu,而 chea 意为子孙。柬埔寨就是 Kumpu 后裔的自称。中国的秦汉时期,这里是扶南属国。到了《隋书》称为真腊,是从 Siem Reap 之名译来的。
柬埔寨旧名 Khmer,《唐书》里称之为吉蔑、阁蔑都是由此而来。对上世纪七十年代末八十年代初国际新闻有印象的人,应该记得红色高棉的出现频率相当高,高棉是 Khmer 后来的译法。元代元成宗铁穆尔曾派温州人周达观出使真腊,周在吴哥呆了一年,回国后写了总结报告《真腊风土记》,开篇说得明白:“真腊国或称占腊,其国自称曰甘孛智。今圣朝按西番经,名其国曰澉浦只,盖亦甘孛智之近音也。” 这段话可以看出三层意思,第一,周达观标题里的真腊,就像今天有人写篇关于日本的东西,起个名儿叫《东瀛十日》或者《扶桑行迹》之类的,纯粹为了拗个复古的姿势。第二,周达观在真腊呆了一年,想来是颇学了几句当地高棉话的,他所说的甘孛智应当是自己揣摩着当地读音翻译成汉语的。第三,元朝总称西域各族为西番,“圣朝” 命名的 “澉浦只”,是从佛经里转来的二手货。
今天通行的 “柬埔寨”,最早的记录是明代万历年间,用“柬” 来对译 kum,今天读来相去甚远,不是古人翻译得不准确,而是 400 多年来汉语发生了变化。一个 “柬” 字,反应的恰是汉语语音古今演变的两条重要规律:舌根音的腭化和 m 尾韵的消失。语言的演变因为地域差异而不平衡,在这场语音演变的马拉松中,北方话跑得比较快,声母 k 受发音部位靠前的韵母影响变成了 j,韵尾 m 也并入了 n,就读成了 jian;粤语跑得比较慢,仍然保持了 “柬” 古时的特征,读作 kam。如同一场凶杀案的现场,法医循着半个模糊的脚印,最终描画出嫌犯的身高体重甚至职业特征普通人大惑不解的译音偏差,恰恰为研究语言演变提供了生动的证据,这样的证据还能在方言中得到印证。
至于那个 “寨”,对应于高棉语的 chea,中国人听来其实还满像的。英语里转写成 dia,大概是从法语 Cambodge 里来的,但若拿这个笑话人家翻得差,又着实五十步笑百步。</p>
<hr>
<p>第 84 页
在不同类型的语言中,语序的重要性不同。汉语是没有形态变化的语言,语序举足轻重,语序一变,“我打你”和“你打我”意思截然不同。即使“饭我吃”这种基本语义关系跟“我吃饭”没有区别的句子,也因为把受动者提到了前面,有指明语义焦点作用,把饭当作一个话题来处理。它不能单独成句,总是要放在特定的环境或上下文当中。比如可能是对比“饭我吃,活儿你干”,跟正常叙述的“我吃饭”有所区别。而在拉丁语、芬兰语当中,虽然有主流语序,但因为每个名词都有标明其语义角色的“格”的变化,有了身份标记,游走起来则变得相当灵活。
语言学家把汉语这种固定词序和通过独立的虚词来表达语法意义的语言称为孤立语,相对应的,德语、法语、拉丁语这种由词的形态变化实现语法作用的称为屈折语。单个汉字无变一身轻,行动却比较受限,必须各安其位;拉丁语里每个名词都要考虑性、数、格,每个动词都有时、体、态,戴着形态枷锁,相对却行动自由。这个世界真是公平。</p>
<hr>
<p>第 88 页
要是会说现今老南京城区八十岁以上的老人家那种保留了入声、分得出尖团的“老南京话”,段位就相当高了,穿到明朝如鱼得水。而且这种口音相当高贵,哪怕后来明朝迁了都清朝设了正音馆,但直到清末,南京官话都是官场和知识阶层的主流口音,享有非常高的地位,当时有“申话不如京话好,南京土白最堪嘉”之说。正因为明清两代作为汉语正音,老南京话相当稳定,会此种口音,当能应付“明穿”“清穿”跨代之需,管用五六百年呢。</p>
<hr>
<p>第 94 页
东汉末年人们开始使用反切注音。据说是因为佛教的传入,某些儒生受到梵音拼音字理的启发,以两个字来注音,取上字的声母,取下字的韵母和声调,拼合即能读出被切字的读音。最初这种注音方式写成“某某反”,因为避讳造反的“反”,唐未改称“某某切”。比如“苏”,注为素姑切,就是取了“素”的声母 s,“姑”的韵母 u 和平声的声调。直到 1918 年北洋政府教育部公布国语注音字母之前,其间的一千多年,反切法是汉语最主流的注音方法。
上字取声,下字取韵,反切的出现,标志着古人开始对汉字音节进行拆分,这也是中国音韵学的开端。不过,因为反切上下字都各有声韵,在拼合时需要掐头去尾,不是那么直接,而且有的韵字数很少,找不到合适的反切字不得不借用旁韵,也不能算十分精确。更何况这方法用了一千多年,若意识不到汉语声韵调都发生了变化,唐人标注的反切,清人又会百般不解。故而音韵学即便在读书人当中也被视为绝学,不敢轻言。</p>
<hr>
<p>第 103 页
其实,用身体作尺子,不是中国人的专美。罗马帝国的查理曼一世规定以他的脚长为“一罗马尺”,英王埃德加规定过,以他拇指的关节长度为“一英寸”,亨利国王规定他的鼻子尖到伸直手臂的中指尖距离为一码。所谓英尺 foot 跟脚是同一个词。脚的长度因人而异,这个英尺如何确定呢?有人说是约翰国王、也有人说是查理国王的脚。不过到十六世纪,德国人另辟蹊径。他们在一个礼拜日,让从教堂里走出来的 16 个男子站在一起,然后将其左脚的长度加在一起,除以 16,求出一个平均的脚长。这就是今天英尺的由来。从王的专权到普通人的平均数,这是时代的进步。
为什么汉语把 foot 翻译成英尺?前阵子有人在微博上发帖,声称手腕到手肘的距离恰跟自己的脚长一致,很多人搬脚比画,纷纷跟帖大呼神奇。其实,被称为测量解剖学鼻祖的达·芬奇早就发现了这个秘密,在他的素描名画《维特鲁威人》中,人手前臂的长度和脚恰是一样的比例。别忘了,汉语中前臂的那根骨头,就叫尺骨。</p>
<hr>
<p>第 179 页
日语除了来自日本民族原来的日常动词和具象名词之外,历史上吸收了大量的外来语,早期是汉语,到了近代明治维新后,除了一些后来还回传到中国的“政治”、“经济”、“民主”、“干部”等用汉字意译的西方文化词汇外,更大量是音译的来自英语、荷兰语、葡萄牙语、法语的现代军事、科技、艺术词汇,在日文中用片假名标示。我的朋友抱怨过他在日本读研究生的时候,计算机课本宛若天书,满篇都是片假名,“给个英文版我大概更明白点。”他苦笑着摇头。在当代,习惯了外来词汇直接拿来就用的日本人,把日文餐桌词汇直接音译成英语,也就是可以理解的事情了。</p>
<hr>
<p>第 190 页
这真让人有点焦虑。焦虑的不是电脑的强大,而是人脑的懒惰。如今电脑能写的,还只是些有固定模式的“陈词滥调”。但是按照计算机深度学习的能力和神经式网络的研究进展,也许它会写得越来越好。但要是人的阅读快感,仅仅来源于那种模式化的玄幻小说,渐渐丧失感受新奇与精微的能力,也许真有一天,强大的机器写作就把唐家三少给替代了。
人类最终能够与机器抗衡的,大概就是那些微妙的东西吧。而微妙,决定了这世界不是骇客帝国。</p>
<hr>
<p>第 214 页
重复,是跟幼儿的心理发展历程紧密相关的。按照弗洛伊德老人家的说法,从母体的保护中降生,面对外部世界毫无还手之力的孩子,都会有一种害怕和无能的感觉,这就是出生创伤,这样的创伤带来焦虑,因为对环境无法预期和控制。而重复的东西,让人获得安全感,那些纷至沓来的固定句型和可以预期的情节,让孩子检验着自己的记忆和期望,因此对于孩子的世界来说,既定的重复情节提供的恰是这样一种似曾相识,从而带来心理上的安全感,同时关键词的替代能够带来些许新鲜感,这就是三段式故事背后的心理依据,甚至这构成了人类文化心理原型,超越种族与时代。</p>
<hr>
<p>第 216 页
语言与思维的关系,是个很有趣的哲学命题。美国语言学家萨丕尔和他的弟子沃尔夫曾经提出过关于语言与思维关系的假设,他们认为所有高层次的思维都倚赖于语言。说得更明白一些,就是语言决定思维,这被称为语言决定论。</p>
<hr>
<p>以上摘自:<br>
<img src="https://img3.doubanio.com/view/subject/l/public/s28243310.jpg" alt="《回锅肉和香菇菜心的语言等级》"><br>
<a href="https://book.douban.com/subject/26559540/">《回锅肉和香菇菜心的语言等级》</a><br>
作者: 李倩<br>
出版社: 商务印书馆<br>
ISBN: 9787100112697</p>
《中东死生门》读书笔记
https://acuario.xyz/others/life-in-the-middle-east-clip/
2023-09-27T18:25:39+00:00
2018-04-19T16:38:46+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>第 IV 页
以色列与巴勒斯坦冲突的故事似乎陷于循环,死结除了政治复杂角力,还在于敌对双方的主流叙述,都拒绝视对方为“人”,而限定为魔鬼。发动大众跟魔鬼作战是容易的,围剿人,则会遭遇各种道义束缚。在我两年的拍摄中,从没有见过纯粹的魔鬼或天使,流泪的流血的都是人。“妖魔化”对方的手法,在全世界各种冲突中都可以见到。</p>
<hr>
<p>第 38 页
在加沙,日常生活与突然死亡之间,赴死是一个特殊的状态,可以延展,可以重复。它是舞台上的一记亮相,是日常生活发生的一次核聚变,它的光芒照亮了日常,令之神圣,但也足以顷刻间摧毁生活。就像观察中国人怎么吃,法国人怎么恋爱,要了解巴勒斯坦人和以色列人,就要看他们怎样对待死亡。</p>……
<p>第 IV 页
以色列与巴勒斯坦冲突的故事似乎陷于循环,死结除了政治复杂角力,还在于敌对双方的主流叙述,都拒绝视对方为“人”,而限定为魔鬼。发动大众跟魔鬼作战是容易的,围剿人,则会遭遇各种道义束缚。在我两年的拍摄中,从没有见过纯粹的魔鬼或天使,流泪的流血的都是人。“妖魔化”对方的手法,在全世界各种冲突中都可以见到。</p>
<hr>
<p>第 38 页
在加沙,日常生活与突然死亡之间,赴死是一个特殊的状态,可以延展,可以重复。它是舞台上的一记亮相,是日常生活发生的一次核聚变,它的光芒照亮了日常,令之神圣,但也足以顷刻间摧毁生活。就像观察中国人怎么吃,法国人怎么恋爱,要了解巴勒斯坦人和以色列人,就要看他们怎样对待死亡。</p>
<hr>
<p>第 46 页
没有多少媒体报道萨希卜的故事,因为他没有炸死其他人我在地图前站了好一会儿。不知道招募萨希卜的人用的什么诱惑。但可以想见,他生长的环境里,赴死的仪式频繁演出,它接管了所有绝望、不如意,乃至希望的去向。它指向为一个政治目的而死,是一切的最后答案。</p>
<hr>
<p>第 68 页
逾越节。耶路撒冷城市边缘,圣约翰受洗堂旁边的一个小咖啡馆。摆设很有创意,中国的洋铁皮壶漆成大红大蓝,描上花花草草。一看菜单,发现这家咖啡馆并不遵守逾越节不能吃含酵食品的规矩。服务小姐笑笑:“我们什么都有。”以色列有两张面孔,一张宗教,一张世俗。</p>
<hr>
<p>第 76 页
注意到胖主唱穿着军裤,我问他是不是在服兵役。其他人起哄说,胖子在耶路撒冷情报部门工作。“在情报部门,你不需要聪明,只要足够聪明。”胖子有几分得意地说。我问他,对巴勒斯坦人来说,什么才是“全力控诉”呢?他也说不清楚,反正“自杀爆炸损害了他们自己”。“2000年流血冲突爆发前,如果我们想派军队进约旦河西岸的巴勒斯坦城市,很犹豫,因为那是巴勒斯坦人的地方,现在一只要有一次自杀爆炸,我们毫不犹豫冲进他们的村庄……”</p>
<hr>
<p>第 89 页
头巾隐藏头发,听说女性的头发被视为引发邪念之物;长袍自然是为了遮盖身体线条。阿拉伯妇女非常爱美,不化妆她们是不会出门的。袍子、头巾、拎包和鞋子颜色必须统一,袍子多为一色,头巾可以斑斓。</p>
<hr>
<p>第 101 页
转上顶楼阳台,金顶清真寺、阿克萨清真寺,历历在目。“‘阿克萨’的意思是极远、天边,”谢姆托夫用英语飞快地说,“但阿克萨不一定在耶路撒冷,阿拉伯人无根据地把阿克萨同耶路撒冷联系在一起,还宣称对这里的主权……不过你可千万别跟穆斯林这么说,也别说这是我说的。”他一再叮嘱。</p>
<hr>
<p>第 113 页
冒着大雨,我和拉纳终于来到伯利恒圣诞教堂前—传说中耶稣诞生的地方。
低头弯腰进了一道小门。“弯腰进入谦卑之门时,别以为我心里不害怕……”美国《洛杉矶时报》女影记者科尔这样回忆。2002 年 4 月,123 个遭到以色列军队围追堵截的巴勒斯坦人闯入圣诞教堂寻求庇护,与以色列军队对峙 39 天,终获和平解决。对峙期间,科尔突破封锁,从这扇“谦卑之门”跑进教堂,拍摄了后来获得普利策新闻奖的照片。入口如此窄小,传说是基督徒为了阻挡穆斯林骑马进入。不管怎么说,为进入圣地而弯腰谦卑,仿佛天设。</p>
<hr>
<p>第 143 页
在一处僻静的小山头脚下,几个巴勒斯坦人沿弯弯曲曲的小道走来。安说,看,这些人穿小路,就可以绕开以色列检查站。“自杀爆炸者就是这样渗透到以色列的?”我问。“有一部分是。安承认。“那么以色列为什么不把这些道路全部封死呢?”“西岸地形错综复杂,与以色列的交界线很长,根本不可能全部堵死。”安还说,吉普车驶过的许多道路正是近几年形成的,因为原来的道路已经被以色列封死。
安认为,修建隔离墙并不能杜绝人弹,真正用意是攫取更多土地。隔离墙并没有按照 1949 年巴以停战分界线,也就是“绿线”修筑,而是越过“绿线”,伸进巴勒斯坦控制区,形成一道实际边界。
隔离墙打破了巴勒斯坦人与土地之间的联系,失去土地的巴勒斯坦人将变成以色列或邻近阿拉伯国家的工厂奴隶,安这样形容。更惊人的是,大部分修建隔离墙的工人是巴勒斯坦人——在失业率达到 70% 以上的约旦河西岸巴勒斯坦城市,这也是一份工作。
吉普车再次上路。在一条5米多宽的土路两侧,各出现一道铁丝网。安指给我看,铁丝网背后各是一个巴勒斯坦村庄。两个相隔仅5米的村庄今后如何往来呢?以列建议修建地下隧道供巴勒斯坦人行走一当然,这得由巴方出钱,而以方控制出入。</p>
<hr>
<p>第 152 页
在失业率高达 75% 的加沙地带,有一份工作实在不易。埃雷兹检查站旁有一个以色列工业园,在那里打工的 1500 多名巴勒斯坦人主要从事钢铁、塑料制品加工,每小时收入 5 谢克尔,一天下来可以挣 50 谢克尔。如此算来,每月收入可以达到 1500 谢克尔,相当于加沙城里一个公司职员的月薪!但工人们否定了我的想法。一星期中有三四天以色列因为‘安全原因’关闭工业区。”另外有一万多名巴勒斯坦人获准出埃雷兹,到附近以色列城镇工作,但每天必须返回加沙地带。
过关的辛苦且不说,最难的是两头受“威胁”。哈马斯等激进组织“恐吓”上班的工人:“给以色列人打工就是背叛巴勒斯坦人!”向工业区发射的卡桑火箭,不止一次落到工人队伍里;而大多数被迫成为“巴奸”、向以色列提供情报的巴勒斯坦人,也出自工人队伍。道理很简单,一张打工证,全家老小的生计。曾经有一名杰哈德官员遭到以色列“定点清除”,“出卖”他的正是自己的远房侄子。侄子去以色列工业区打工,从姓氏上被以色列方面发现他同那名杰哈德官员来自同一家族。摆在他面前的问题就是:要么出卖叔叔,要么失业回家。</p>
<hr>
<p>第 198 页
“Abraham”和“Ibrahim”分别是希伯来语、阿拉伯语对“亚伯拉罕”的不同发音。根据《圣经·旧约》和《古兰经》记载,亚伯拉罕是犹太人和阿拉伯人共同的祖先。犹太人是小儿子,亚伯拉罕同发妻生的;阿拉伯人是长子,亚伯拉罕跟婢女生的。</p>
<hr>
<p>第 219 页
黑漆漆的路上,他教我辨认,橙色灯光的地方就是犹太人住的,白色、青色的灯光,便是巴勒斯坦人住地,夜里很容易辨认。他说,以色列不许巴勒斯坦人用橙色灯泡,以示区别。</p>
<hr>
<p>第 223 页
说起埃拉特,施罗莫露出笑容。这座城市离巴勒斯坦区域较远,几乎没有遭受过恐怖袭击。以色列有个地下赌场,专赌下次自杀爆炸在哪里发生。耶路撒冷“一赔二”,埃拉特“一赔二十”可见后者安全系数较高。</p>
<hr>
<p>第 225 页
两分钟的工夫,莫蒂回来,手里多了支烟。他的英语不是很好,父母是摩洛哥来的犹太人,所以会几句阿拉伯语;阿拉伯语中的一些单词和犹太人使用的希伯来语相近,我也学了几句,所以我们就 3 种语言(英语、阿拉伯语、希伯来语)混着说,外加手势比画。</p>
<hr>
<p>第 227 页
聊天归聊天,安德烈从来没有放松对我的检查。尽管他已经非常清楚我的笔记本电脑什么品牌,开关在哪里,背景照片是什么,甚至化妆包里有多少小零碎儿,通常什么颜色的外套……安德烈每次还是戴上一次性手套,逐一翻检,嘴里重复着“请谅解,请谅解……”
两个月后,埃雷兹发生汽车连环爆炸袭击,此后安全控制陡然加强。记者不再享受“贵宾通道”,改走巴勒斯坦工人通道,而且至少等候两小时才能从通道进入检查大厅。终于被姗姗而来的以色列士兵带入检查大厅,接受安德烈检查时,我向他抱怨“见到你真难啊,我等了两个小时!”他的脸更加阴沉:“非常抱歉,现在形势变了,但是你不知道我们面对多少压力,每天我离开家时,妻子都对我说:‘希望晚上见到你回来’……”
几天以后,安德烈脖子上多了杆乌兹冲锋枪。</p>
<hr>
<p>第 238 页
他指着路边背书包的孩子,看,如果犹太人盯上了我,一颗炸弹掉进我车里,这些小孩也完了。你看,那个小孩,喏,那个蓝衬衣的,他难道不是平民吗?不是无辜的吗?
我问,那你怎么看自杀爆炸呢?公共汽车上,餐馆里,那些以色列人不是平民吗?不是无辜的吗?他回答说,你说得对,但是我们巴勒斯坦人“没有飞机,没有坦克,只有自己的身体”。</p>
<hr>
<p>第 314 页
十多年过去,今天看待巴以冲突,犹如活化石。仍然是旧的战争思维:为了土地。悲哀的是,就连整个中东的焦点,都转向了伊朗核问题、新能源革命和国际恐怖主义。今天世界上发生着两件极其不平等的事情:一是高科技迅猛发展,人类命运“共同感”加强;二是主要国家政府仍然提高军费,各自提防。换句话说,形成两幅落差很大的画面:一群人或许殖民火星,同时另一群人在地上用石头相互攻击。未来的科技发展,可能让现在的主要政治问题都变得荒谬,彻底改变人类社会的权力结构。没有人知道,百年冲突,或许会以意想不到的方式终结?几乎可以肯定的是,未来巴以问题不再重要,但那里的人们,他们的命运不该被遗忘。</p>
<hr>
<p>以上摘自:<br>
<img src="https://img3.doubanio.com/view/subject/l/public/s29495542.jpg" alt="《中东死生门》"><br>
<a href="https://book.douban.com/subject/27089521/">《中东死生门》</a><br>
副标题: 巴以行走观察 <br>
作者: 周轶君 <br>
出版社: 中信出版集团 <br>
ISBN: 9787508676432</p>
《发条橙》读书笔记
https://acuario.xyz/others/a-clockwork-orange-clip/
2023-09-27T18:25:39+00:00
2017-12-11T01:30:28+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>引言<br>
由于人在定义中就被赋予了自由意志,可以由此来选择善恶。只能行善,或者只能行恶的人,就成了发条橙——也就是说,他的外表是有机物,似乎具有可爱的色彩和汁水,实际上仅仅是发条玩具,由着上帝、魔鬼或无所不能的国家(它日益取代了前两者)来摆弄。彻底善与彻底恶一样没有人性,重要的是道德选择权。恶必须与善共存,以便道德选择权的行使。人生是由道德实体的尖锐对立所维持的。电视新闻讲的全是这些。不幸的是,我们身上原罪深重,反而认为恶很诱人,破坏比创造更加容易,更加壮观。我们喜欢看宇宙分崩离析的幻象,哪怕吓得裤子拖地。</p>
<hr>
<p>第 23 页<br>
“是书啊?”我说道,“你正在写的是书啊?”我把嗓音弄得很沙哑,“我对会写书的人始终十二万分地钦佩。”我看了看顶上的一页,上面有书名《发条橙》,然后说:“这书名颇为傻冒。谁听说过上了发条的甜橙?”接着我以牧师布道式高亢的嗓音朗读了片断:“——硬是强迫生机勃勃、善于分泌甜味的人类,挤出最后一轮的橙汁,供给留着胡子的上帝的嘴唇,哎哟,生搬硬套只适于机械装置的定律和条件,对此我要口诛笔伐——”丁姆听着又发出了唇乐,我也忍不住笑了。于是我撕破纸头,把碎片播撒在地板上。</p>……
<p>引言<br>
由于人在定义中就被赋予了自由意志,可以由此来选择善恶。只能行善,或者只能行恶的人,就成了发条橙——也就是说,他的外表是有机物,似乎具有可爱的色彩和汁水,实际上仅仅是发条玩具,由着上帝、魔鬼或无所不能的国家(它日益取代了前两者)来摆弄。彻底善与彻底恶一样没有人性,重要的是道德选择权。恶必须与善共存,以便道德选择权的行使。人生是由道德实体的尖锐对立所维持的。电视新闻讲的全是这些。不幸的是,我们身上原罪深重,反而认为恶很诱人,破坏比创造更加容易,更加壮观。我们喜欢看宇宙分崩离析的幻象,哪怕吓得裤子拖地。</p>
<hr>
<p>第 23 页<br>
“是书啊?”我说道,“你正在写的是书啊?”我把嗓音弄得很沙哑,“我对会写书的人始终十二万分地钦佩。”我看了看顶上的一页,上面有书名《发条橙》,然后说:“这书名颇为傻冒。谁听说过上了发条的甜橙?”接着我以牧师布道式高亢的嗓音朗读了片断:“——硬是强迫生机勃勃、善于分泌甜味的人类,挤出最后一轮的橙汁,供给留着胡子的上帝的嘴唇,哎哟,生搬硬套只适于机械装置的定律和条件,对此我要口诛笔伐——”丁姆听着又发出了唇乐,我也忍不住笑了。于是我撕破纸头,把碎片播撒在地板上。</p>
<hr>
<p>第 34 页<br>
此后,我听了美妙的莫扎特《朱庇特交响曲》,并出现不同面孔遭到踩踏和喷射的新图景,这时我想,越过梦境前只听最后一张唱片了,我想听古典,强烈而很坚定的东西,所以就选了巴赫的《勃兰登堡协奏曲》,只配了中低音弦乐器。听着听着我产生了与以前不同的快感,并再次看到那晚撕破的纸上的这个书名,事情发生在一个名叫“家”的小屋,时间已经显得十分悠远。书名讲的是一只上了发条的甜橙。听着巴赫,我开始更深刻地理解个中意义;而心中则充盈着那位德国音乐大师带来的棕色的极致美感。我想到,我愿意更狠毒地推搡那夫妻俩就在他们家的地板上,把他们撕成碎片。</p>
<hr>
<p>第 38 页<br>
“呃,”德尔托得说,“我对你也说惯了,小同学,你要注意啊,你非常清楚,下次就不是教养学校的问题喽。下次就是送上审判台了,我嘛是前功尽弃。你若对自己可怕的一生毫不在乎的话呢,至少也该为我稍微想想吧;我为你出过力流过汗的。悄悄告诉你吧,我们每改造失败一个人,都会得到一颗大黑星;你们每有一个人进铁窗,我们都要做失败忏悔的。”</p>
<hr>
<p>第 38 页<br>
接着他以万分沉痛的口吻说,尽管仍然在摇动着旧摇椅:“你们这些人到底中什么邪啦?我们正在研究这个课题,已经搞了要命的近百年了,却毫无进展。你的家庭很不错,父母很慈爱,脑袋瓜也不赖。是不是有什么魔鬼附在你的身上?”<br>
“没有人向我灌输任何东西,先生,”我说,“我已经很久没有落入条子之手了。”<br>
“这正是我所担心的,”德尔托得叹息道,“是太久了,还怎么保持健康。据我估算,你快到落网的时候了。所以要警告你,小同学,放规矩点,不要让漂亮年轻的长鼻子蒙尘,对吧。我的意思清楚吗?”<br>
“就像清澈的湖水,先生,”我说,“就像盛夏的蔚蓝天空一样清楚。包在我身上吧。”我朝他露齿一笑。</p>
<hr>
<p>第 39 页<br>
我说:“这挺公正,但很可惜,老爷们,因为牢笼生活我实在忍受不了啊。我的努力方向是,趁未来还向我伸出洁白的手臂的时候,好自为之,再也不要被警察捉了去;要提防别人手持刀子追上来刺一刀;不要在公路上飙车,以免金属件扭曲,碎玻璃飞溅,鲜血喷洒,凝成最终的合唱。”这话很公允,但是,弟兄们哪,他们不厌其烦咬着脚指甲去追究不良行为的“根源”,这实在令我捧腹大笑。他们不去探究“善行”的根源何在,那为什么要追究其对立的门户呢?如果人们善良,那是因为喜欢这样,我是绝不去干涉他们享受快乐的,而其对立面也该享受同等待遇才是。我是在光顾这个对立面。而且,不良行为是关乎自我的,涉及单独的一个,你或我,而那自我是上帝创造的,是上帝的大骄傲、大快乐。“非自我”是不能容忍不良行为的,也就是政府、法官、学校的人们不能允许不良行为,因为他们不能允许自我。弟兄们哪,我们的现代史,难道不是一个勇敢的小自我对抗这些大机器的故事吗?对于这一点,我跟你们是认真的。而我的所作所为,是因为喜欢做才做的。</p>
<hr>
<p>第 101 页<br>
电灯熄灭,你们的小说叙事者兼朋友——鄙人孤零零地坐在黑暗中,心中万分恐惧,身体动弹不得,眼睛闭不上,什么都不能动。此时,电影开始放映,喇叭里传出响亮的背景音乐,十分猛烈,充满了不和谐音。银幕上的画面出现了,没有片名和演职员名单。场景是大街,可以是任何城镇的任何街道是个黑夜,点着路灯。电影的质量是符合专业标准的,不像偏僻街道居民家中放映的那种肮脏电影,会出现闪亮和色斑。音乐不停地嘭嘭送出,令人毛骨悚然。画面上出现一个老头子,非常衰老,在街上踯躅,而两个穿着时髦的家伙扑上去,这时依然流行细腿裤,当然宽领带已经让位于真正的领带了。两个人开始戏弄老头,可以听见尖叫和呻吟,十分逼真,甚至能听清两个拳打脚踢者的喘气声。他们把老头揍成了肉饼,拳头啪啪啪打个不停,布拉提撕开后,赤膊的老头还领受了一顿靴子踢,直到血淋淋的躯体躺倒在明沟的污泥中才作罢,两个流氓迅速逃走了。下面是挨揍老头的头部特写,流淌的红血血真漂亮。真有趣,现实世界的色彩,只有在银幕上才能看真切。</p>
<hr>
<p>第 104 页<br>
那天被迫观看的其他可怕镜头,弟兄们,我实在不想描述了。这挖空心思的布罗兹基大夫、布拉农大夫和其他白大褂哟,记得还有这转动旋钮、观察仪表的姑娘,肯定比国监内的任何囚犯更加肮脏不堪、臭不可闻。我万万没料到,有人甚至会想得出将强迫我看的东西拍成电影,而且把我绑在椅子上,眼睛绷得大大的。我别无他法,也就是大声呼叫,请他们关掉,关掉,这稍微掩盖了打斗和戏弄的声音,压低了背景渲染音乐。我终于看完了最后一部电影,布罗兹基大夫打着哈欠,以厌烦的口吻说:“我看第一天就这样算了,你说呢,布拉农大夫?”此刻,你们可以想见我的解脱心情。电灯亮了,我坐在那儿,格利佛就像制造痛苦的庞大发动机在噗通噗通直跳,嘴巴干涩,唾沫不少,感到可以把断奶以来吃过的每一口食物呕出来,弟兄们哪。</p>
<hr>
<p>第 122 页<br>
布罗兹基大夫对观众说:“请看,我们的实验对象通过被迫趋向恶,反而被迫趋向善。暴力意图伴随着猛烈的切身痛感。为了消除痛感,不得不转向截然相反的态度。有问题吗?”<br>
“选择权。”一个浑厚的声音说。我发现这是教诲师呀。他没有真正的选择权,对不对?他有利己之心,害怕痛感,所以被迫走向自我糟蹋的古怪行为。其虚假性显而易见。他不再胡作非为,同时也不再能够作道德选择。”<br>
“这问题很微妙,”布罗兹基大夫微笑着,“我们所关心的不是动机,不是高尚的伦理规范,而仅仅是减少犯罪——”<br>
“还有,”那衣冠楚楚的大部长插话道,“缓解监狱的人满为患。”</p>
<hr>
<p>第 125 页<br>
“他会成为你的好基督徒的,”布罗兹基大夫大声说,“准备转过另外一边脸给你打,准备自己上十字架,而不是送人家上十字架;他即使想到捏死个把苍蝇,都会打心眼里感到恶心。”这话倒没错,弟兄们,他提起捏死苍蝇的时候,我感到一点点恶心,便尽力使自己想着用糖喂苍蝇,把它当做要命的宠物来照料,才消退了恶心和疼痛。“改邪归正了,”他喊道,“在上帝的天使面前真欢乐。”</p>
<hr>
<p>第 146 页<br>
他们动手的时候,驾驶员一直坐在方向盘前,边抽烟边看书。汽车里有灯光可供看书,他根本不看比利仔和丁姆对叙事者鄙人的行动。他们的所作所为我也不想详述了,只听农机马达声、秃枝鸟鸣声衬托着喘气声、捶打声,只见汽车灯光中有烟雾热气,驾驶员平静地翻动书页,而在此期间,他们一直在“修理”我,弟兄们哪。然后,我也分不清是比利仔还是丁姆说:“我看差不多了,哥们儿,你说呢?”接着他们每人给我的面孔最后打一拳,我倒下,躺在草地上。天气寒冷,而我一点没有感到冷。他们掸掸袖口,穿戴好刚才脱掉的头盔和上衣,回到了车上。“后会有期,亚历克斯。”比利仔说,丁姆只是发出小丑式的大笑。驾驶员看完那页,把书放好,随之发动汽车,向城里开去,我的前哥们儿和前敌人在挥手。我直挺挺躺着,蓬头垢面精疲力竭。</p>
<hr>
<p>第 149 页<br>
“又一个受害人,”他叹息着,“现代受害人。我去拿威士忌,然后必须将伤口稍加清洗。”他走开了。我扫视一眼这舒适的小房间,简直到处都是书,一个壁炉,几把椅子;不知怎么,看得出屋子里没有女主人。桌上有一架打字机,乱堆着大量的文稿,我记得这家伙是个作家。《发条橙》,就是它。它在我脑海中萦绕不去,真有趣。但我不能泄露出来,我正需要主人的帮助和善心呢。那些可怕的狗杂种在白大楼里就是那样整治我的,迫使我急切地依赖帮助和善心,同时渴望自己也能提供帮助和善心,如果有人愿意接受的话。</p>
<hr>
<p>第 152 页<br>
“我想你确是犯了罪,但刑罚实在不相称。他们已经把你变成了非人的东西,你再也没有选择的权利。你已经委身于社会所接受的行为,成了台行善的小机器。这一点我看得一清二楚——无非是意识域边缘条件反射的营生罢了。音乐、性行为、文学艺术,全都必须成为痛苦的来源,而不是快乐的源泉。”<br>
“对的,先生。”我说,一边吸着这位善人给的软木过滤嘴香烟。<br>
“他们一贯贪多务得,”他说,心不在焉地擦干一只盘子,“但其基本意图是真正的犯罪。不会选择的人,就不再是人了。”</p>
<hr>
<p>第 154 页<br>
那里还有三两个书架,不出我所料,果然有一本《发条橙》,书的背面,书脊上,写着作者的名字——F.亚历山大,上帝呀,我想道,他也叫亚历克斯啊。我翻了翻,身穿他的睡衣,赤着脚,却一点不感到冷,整个屋子很暖和;不过,我看不出书是讲什么的。它的写作风格似乎非常疯狂,充斥着“哪”、“啊”之类的废话,但大概的意思是,如今的人们都变成了机器,他们、你们、我、他,还有拍我的马屁吧——外表却分明是自然生长的水果。F·亚历山大似乎认为,我们都生长在上帝种植的世界果园中他称之为世界之树之上,我们的存在是因为上帝需要我们来解渴,爱的饥渴云云。</p>
<hr>
<p>第 162 页<br>
我醒来时,可以听到墙上传出音乐声,非常响亮,是它把我拖出了那点点瞌睡。那是我十分熟悉的交响乐,已经好几年没有欣赏过了。它是丹麦人奥托·斯卡德里克的《第三交响曲》,是响亮狂热的作品,特别是第一乐章,正在放的就是这一章。我兴致勃勃、快乐地听了两秒钟,接着疼痛和恶心排山倒海地压过来,我的肚子深处开始呻吟。就这样,当初这么热爱音乐的我爬下了床,一边哎哟哎哟地喊叫,接着嘭嘭嘭地敲墙,一边喊道:停下,停下,关掉!”但音乐照放不误,而且显得更响亮了。我向墙上击拳,直到骨节全都是红红血和撕脱的皮,喊叫喊叫啊,但音乐没有停止。然后我想,我得逃出去,于是踉踉跄跄地出了小卧室,冲向公寓的前门,但门反锁上了,根本出不去。与此同时,音乐越来越响亮,好像有意折磨我似的,弟兄们哪。于是,我把手指深深地插入耳朵,可长号和铜鼓声透过手指来还是很响。我再次喊叫,让他们停止,捶打着墙壁,但毫无作用。“哎哟,我怎么办呢?”我独自哭泣着,“上帝保佑我吧。”我疼痛而恶心地满公寓摸索,试图把音乐关掉,呻吟似乎是发自腹中深处。此刻,在起居室桌上那堆书本、纸头上面,我发现了自己不得不做的事情,即图书馆里的老头们、假扮成警察的丁姆和比利仔没让我做成的事情,也就是干掉自己,一死了之,永远离开这邪恶凶残的世界。我看到一份传单封面有“死”字,尽管是《政府去死吧》就像命中注定一样,另一份小传单的封面有一扇打开的窗户说:“打开窗户放进新鲜空气、新鲜观念、新鲜的生活方式。”我知道了,它告诉我,跳窗可以结束一切。也许会有一时的疼痛,然后是永远永远永远的长眠。</p>
<hr>
<p>第 179 页<br>
天色很黑,刀割般的寒风越刮越猛,四周行人很少很少。巡警车载着凶神恶煞般的条子开来开去游弋,不时可见三两个年轻的警察在街角处跺脚取暖,在寒风中喷着热气,弟兄们哪。我想,如今条子对抓获的人极尽折磨之能事,大概大部分的超级暴力和烧杀抢掠已经销声匿迹了吧,其实,现在的形势成了调皮捣蛋的纳查奇和不失时机舞刀弄棍,乃至拔枪相向的条子之间的械斗。而这些天困扰我的问题在于,我已经什么也不在乎了。仿佛某种温柔之气侵入了体内,而我却不懂得为了什么。当时,我不知道自己到底想要什么。连喜欢躲进小室聆听的乐曲,也属于以前要耻笑的曲目,弟兄们。我现在更爱听小小的浪漫歌曲,即所谓的“德国抒情歌曲”,是钢琴伴唱的,很恬静,很有思慕情调,而不是从前那样全是大乐队,身体躺倒在床上,夹在小提琴、长号、铜鼓之间。我的体内正在发生蜕变,我不知道那是病变,还是他们那次在我身上注入的东西在捣鼓我的格利佛?说不定它在逼我走向真正的疯狂。</p>
<hr>
<p>附录《那不是我的发条橙》<br>
《时代》周刊说:“本书也许看似一本淫秽惊悚的小书,但伯吉斯用英语写了一部珍品——一部哲理小说。这一点也许会被忽视,因为小说主人公说的都是纳查奇语,以便给予他应有的特殊身份—半人半非人。这个‘垮掉的一代’的斯塔夫罗金的朝圣之路是一篇严肃而成功的道德随笔。伯吉斯直截了当地认为作为恶人的亚历克斯比作为一个善良的僵尸的亚历克斯更像是一个人。机械社会的发条决不能冒充道德选择的有机生命。如果恶不能被接受为一种可能性,那么善就是无意义的。”</p>
<hr>
<p>以上摘自:<br>
<img src="https://img1.doubanio.com/lpic/s29066459.jpg" alt="《发条橙(纪念版)》"><br>
<a href="https://book.douban.com/subject/26882001/">《发条橙(纪念版)》</a><br>
作者: <a href="https://book.douban.com/author/4506326/">Anthony Burgess</a><br>
译者: 王之光<br>
出版社: 译林出版社<br>
ISBN: 9787544764759</p>
《Google模式》读书笔记
https://acuario.xyz/others/how-google-works-clip/
2023-09-27T18:25:39+00:00
2017-12-11T01:21:24+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>第 27 页<br>
科技對消費者產生重大影響,對企業的影響更大。以經濟學的術語來說,當產業的主要生產要素成本曲線下移時這個產業就將面臨大規模的變化。今天,有三項生產要素變得更便宜了:資訊(Information)、連接性(Connectivity)、電腦運算能力(Computing power),這影響每個涉及這三項生產要素的成本曲線,勢必造成破壞性的結果。許多原來就在市場的公司(也就是網際網路問世前成立的公司)以往建立及發展事業的基本假設是稀有性:稀有的資訊,稀有的通路資源和市場研究,或是稀有的選擇和貨架空間。但如今這些生產要素非常充裕,降低或消除產業與市場的進入障礙,使整個產業來到徹底改變的成熟時機。</p>
<hr>
<p>第 41 页<br>
你可能不認為自己是創業家,但其實你是。你可能有個構想,你相信這個構想會改變一切;你可能有一個雛型概念,甚至有一項產品的第一個版本。你聰明、有抱負,獨自或和你的小團隊委身在會議室、車庫、辦公室、餐廳、公寓或宿舍裡,就算你做著某些事,不管是讀書、工作,或和小孩及配偶相處的時候,你仍然在想著你的那個構想。</p>……
<p>第 27 页<br>
科技對消費者產生重大影響,對企業的影響更大。以經濟學的術語來說,當產業的主要生產要素成本曲線下移時這個產業就將面臨大規模的變化。今天,有三項生產要素變得更便宜了:資訊(Information)、連接性(Connectivity)、電腦運算能力(Computing power),這影響每個涉及這三項生產要素的成本曲線,勢必造成破壞性的結果。許多原來就在市場的公司(也就是網際網路問世前成立的公司)以往建立及發展事業的基本假設是稀有性:稀有的資訊,稀有的通路資源和市場研究,或是稀有的選擇和貨架空間。但如今這些生產要素非常充裕,降低或消除產業與市場的進入障礙,使整個產業來到徹底改變的成熟時機。</p>
<hr>
<p>第 41 页<br>
你可能不認為自己是創業家,但其實你是。你可能有個構想,你相信這個構想會改變一切;你可能有一個雛型概念,甚至有一項產品的第一個版本。你聰明、有抱負,獨自或和你的小團隊委身在會議室、車庫、辦公室、餐廳、公寓或宿舍裡,就算你做著某些事,不管是讀書、工作,或和小孩及配偶相處的時候,你仍然在想著你的那個構想。</p>
<hr>
<p>第 42 页<br>
所以,就算你不是習慣穿著連帽運動衫的科技人,就算你沒有取得創投提供的七位數美元支票,也不代表你無法創造出下一個盛事。你需要洞悉產業正在快速轉變,你要有勇氣冒險,成為這轉變中的一分子,願意而且吸引到最優秀的智慧創做者,領導他們實現轉變。</p>
<hr>
<p>第 49 页<br>
請你做個小小的思考實驗:想想你曾經任職過的一家公司,接著,請你詳述它的使命,你說得出來嗎?如果說得出來,你相信嗎?你覺得它確實、誠實反映公司與員工的行動和文化嗎?還是它像是一群行銷和公關人員在一個晚上邊喝啤酒、邊查詞庫所想出來的文詞?這些字句類似這樣:「我們的使命是透過知識、創造力與我們員工的努力,和我們的客戶建立至高無上的夥伴關倸,為我們的客戶創造價值,並為我們的股東創造優異成果。」哇,面面俱到,不是嗎?提到了客戶,提到了員工,提到了股東。提出這份使命的是雷曼兄弟公司(Lehman brothers),至少在 2008 年破產之前是這麼說的。</p>
<hr>
<p>第 56 页<br>
當你伸手就可以觸碰到某個人的脣膀時,就不會有什麼東西會阻礙溝通和點子意見交流。傳統的辦公室安排有個別隔間和辦公室,目的是保持穩定安靜狀態。團隊的人際互動大多是計劃性的互動(聚集在會議室裡開會),或是偶然的互動(在走廊、茶水間或停車場相遇)。這其實是倒行逆施,穩定狀態應該是高度互動,喧譁、擁擠的辦公室,充滿興奮的活力。而員工覺得受過團體刺激後,可以選擇退避至安靜的地方。正因此,我們的辦公室有很多僻靜設施:餐廳和小廚房裡有隱蔽的角落、小會議室、戶外露臺與空間,甚至還有打盹艙。但是,當員工回到辦公座位時,他們周遭應該充斥著自己的隊友。</p>
<hr>
<p>第 61 页<br>
河馬(Hippo)是世界上最危險的一種動物,跑步速度遠超乎你的想象,牠們性格凶暴,能把侵犯領域或出現在行進途中的敵人踩死或咬成兩截。公司裡的河馬也很危險,它們是所謂「最高薪資的人的意見」( Highest-Paid Person's Opinion,HIPPO)。說到決策品質,基本上和薪資高低無關,經驗固然重要,但前提是要構成一個有說服力的勝出論據,經驗才會被採用。不幸的是,在多數公司,經驗本身被當成有說服力的勝出論據,經驗多的人說了算,我們稱這種組織為「年資統治體制」(tenurocracy),因為在這些組織權力來自年資,不是功績或創造的價值。這使我們想昔日網景公司( Netscape)執行長吉姆·巴克斯戴爾(Jim Barksdale)說過的話:「如果有資料的話,我們就看資料;如果我們沒有資料,只有意見的話,那就照我的意見去做吧!」<br>
當一個組織停止只聽「河馬」的意見時,就會開始形成功績體制,我們的同仁修娜·布朗(Shona Brown)簡單清楚地描述這種組織:「最重要的是意見或點子的品質,而不是誰提出的建議。」這聽起來很容易,其實不然。想建立功績體制,必須讓可以只靠命令來指揮統治的「河馬」和那些冒著被踩死的危險丶勇於支持品質和功績制的智慧創做者都有平等参與權。</p>
<hr>
<p>第 64 页<br>
「組織改造」是企業詞彙當中最受鄙視的一個名詞,大概只有「外包」和「80 張投影片簡報」可以比得上。一位高階主管認定問題根源是公司的組織架構,所以如果改變組織架構,一切就能迎刃而解。於是,公司突然從中央集權架構改變成地方分權架構,或是從功能部門架構改變成事業單位架構。結果,一些主管是「赢家」,其他主管變「輸家」,同時大部分員工心神不定,不知道自己是否還有飯碗,如果有的話,還有煩惱他們的新上司是誰,他們還能不能保住靠窗的好座位。過了一、兩年,某位主管(或者,很有可能仍然是那位主管)發現,公司仍然有問題,於是下令再來一場組織改造。這就是企業界可怕的「指定執行次數迴圈」(for loop)。</p>
<hr>
<p>第 76 页<br>
你可以透過賦予員工職責和自由來管理這個層面,無需下令他們工作到更晚,或是早點下班和家人相處,只要叫他們管好自己分內的事給予他們空間和自由,他們自己會安排時間,把工作做好。前 Google 高階主管、2012 年接掌雅虎執行長的瑪麗莎·梅伊爾(Marissa Mayer)是矽谷最知名的職業婦女,她提到,導致職業倦怠的不是工作過度,而是必須放棄對你而言重要的事所產生的憤怒。讓你的智慧創做者自我控管,他們通常會對工作與生活的平衡作出最佳決定。</p>
<hr>
<p>第 77 页<br>
人的時間與精力有限,工作超過負荷的確會導致職業倦怠,但是有關於職業倦怠的研究顯示,缺乏自我控管也是一個主因:其他原因還包括薪資不足、社區問題、欠缺公平性、價值觀衝突。職業倦怠這個主題的知名研究者、心理學家克莉絲汀娜·馬斯拉奇(Christina maslach)認為你,職業倦怠是人不適合他的工作的一種徵狀,她也認為,組織有責任創造更人性化的工作環境。参見 Christina Maslach and Michael P.Leiter, The Truth about Burnout: How Organizations Cause Personal Stress and What to Do About It, (Jossey-Bass, 1997).</p>
<hr>
<p>第 77 页<br>
我們雖然不提倡「工作與生活平衡」,但我們鼓勵員工好好休假。如果有人認為他對公司重要到令他不能休假一、兩週,認為這會導致公司運作停擺的話,那就代表公司有更大的問題需要解決。一家公司不可能、也不應該有任何一個不可缺少的人。偶爾會遇到有員工故意創造這種情況,也許是他們的自負心理作祟,或是誤以為「不可缺少」就能保障飯碗。遇到這種人,務必讓他們好好休個假,並且安排代班人。等他們休假回來,精神與鬥志恢復,也體認到自己並不是那麼「必不可缺」,而代班人也會變得更有信心。</p>
<hr>
<p>第 80 页<br>
一家傑出的新創公司、一個出色的計劃、一份好工作應該充滿樂趣,如果你賣力工作,卻完全無法從中獲得任何樂趣,那一定有問題。樂趣有部分是來自期望未來成功的心情,但有很大的部分來自和公司同仁共事,一起開玩笑。<br>
多數公司嘗試製造玩樂,比方說,舉辦年度公司野餐(節慶派對、週五在公司外舉辦的活動)、有玩樂的音樂、有玩樂的獎品、有可以讓同事出糗的趣味竸賽、有顔面彩繪/小丑/算命、供應玩樂的食物(但不供應玩樂的酒品)。你參加這些活動,在這之中玩樂。不過,這類玩樂活動有個問題:它們很無趣。</p>
<hr>
<p>第 91 页<br>
施密特進入 Google 約 6 個月後,此時的他相當熟知公司「賺錢不必為惡」(Don't be evil)的座右銘,這是工程師保羅·布海(Paul buchheit)和阿密·帕泰爾(Amit patel)在公司開創初期的一次會議提出的。不過,施密特完全低估這句簡單座右銘在 Google 公司文化中深植内化的程度。施密特出席公司的一場會議,與會者辯論應不應該對廣告制度做出一項改變,這項改變的優點有可能為公司帶來相當可觀的收入。其中一位工程領導人捶桌子說:「我們不能這麼做,這是惡行。」會議室突然鴉雀無聲,這個場面就像在美國舊西部世界的撲克牌牌局中,有個玩家指挫另一個玩家是老千,然後其他的人停止出牌,等候某個人說話。施密特心想,哇,這些傢伙對這種事很認真呢。接下來是冗長的討論,最終這項改變沒通過。</p>
<hr>
<p>第 102 页<br>
當市場調查詢問潛在顧客最在意的事中,排名第一的是速度時,公司便在其行銷中凸顯這一點。但是,儘管有線寬頻的速度的確很快,但用戶在開始使用這份服務後,他們真正喜愛的特性是「隨時上線」;他們不需要等候撥接,不想聽到數據機發出的嘶嘶聲,也不想等伺服器用來讓他們連結上網品質達到最佳點。羅森柏格與他的同事針對用戶說的需求來行銷,但市場研究不會告訴你該解決顧客無法想到、但可以解決的問題。為顧客提供他們想要的東西,重要性與價值比不上為顧客提供他們還不知道自己會想要的東西。</p>
<hr>
<p>第 106 页<br>
我們很喜歡用成人娛樂產業的例子來解釋,如何把原本用來解決狹隘問題的方法當作基礎,進一步發揚光大,這個例子跟早期技術採納者有關。當 Google 搜尋引擎事業規模開始飛速成長時·這個搜尋引擎平台上最熱門的一些搜尋是成人相關主題。在當時,色情過濾功能非常缺乏成效,因此我們讓一小群工程師根據美國聯邦最高法院法官波特·史都華( Potter Stewart)對色情的定義:「看到它時,我就知道它是色情」,研究「Google 它時,我就知道它是色情」的問題。他們最終成功了,靠的是多項技術洞見的組合:他們變得很善於了解一張圖像的「内容」(應該說是「膚色」),而且只需看用戶和圖像互動的情形,就能判斷「背景」(當某人搜尋色情相關字詞,有個影像來自醫學教科書時,他們不太可能點選它,就算點選了,也不會在這個網站停留很久)。我們很快就發展出一個「安全搜尋」( Safe Search)的過濾功能,遠比當時網路上的任何過濾器更能有效攔截不適當的影像。這就是對一個狹隘問題(過濾成人内容)發展出的解決方法(安全搜尋)。<br>
但為何要就此打住呢?接下來幾年,我們把用來解決色情問題的技術應用於更廣泛的用途。我們使用安全搜尋發展出的數百萬種內容搜尋模式(也就是使用者對各種影像的反應模式),改善對搜尋影像(任何影像,不一定是色情影像)關聯性高低評估的能力。我們增加功能,讓使用者可以進一步搜尋和搜尋結果相似的影像,例如:「我喜歡那張優勝美地(Yosemite)的照片,請幫我搜尋和這相似的照片」。我們後來還開發岀另一種能力:不以輸入關鍵字(例如「Half dome,yosemite」)來搜尋,改用一張相片(你去優勝美地時拍攝的半圓頂〔Half dome〕相片)來搜尋。這些功能全都衍生自我們一開始為安全搜尋色情過濾功能發展的技術,所以當你在螢幕上看到幾乎和你拍攝的優勝美地相片模一樣的相片時,你應該感謝成人娛樂產業,是這個產業促使我們發展出的技術能夠進一步應用在你身上。</p>
<hr>
<p>第 112 页<br>
網際網路有一個極具吸引力、且被低估的層面:它大幅擴展建立平台的潛力,這並非僅指科技業的平台,而是指任何一個產業的平台。<br>
……<br>
平台的例子不勝枚舉,Square 為小型企業提供支付系锍服務、Nike FuelBand 提供運動資訊的手環、 Kickstarter 是創意專案的群眾集資平台、MyFitnessPal 是减肥者的平台、耐飛利(Netflix)是影片娛樂平台、Spotify 是線上音樂平台。這些公司以新方式結合現有技術元件,重新想像現有事業,它們為顧客和事業夥伴建立互動平台,並使用這些平台來創造高度差異化的產品與服務。這種模式幾乎可以應用在每個產業,包括旅遊、汽車、服飾、餐廳、食品、零售,隨著更多人使用,每個產業幾乎都可以創造出更好的產品。<br>
20 世紀的經濟和 21 世紀的經濟不同,20 世紀由巨大封閉的網絡宰制,21 世紀則是由全球性的開放網路引領風騷。我們周遭充斥著平台機會,成功的領導人是那些能夠發掘這些機會的領導人。</p>
<hr>
<p>第 139 页<br>
多數人在為一個職缺徴才時,總是尋找過去在這種職務角色上有優異表現的人,這不是去尋找學習型動物。幾乎所有徵人啟事列出的首要絛件裡都是「有相關經驗」,比方說,有個職缺是機件設計師,開出的首要資格是要求是 5 到 10 年的機件設計經驗,並擁有大學相關學系學位。<br>
其实,把專業看得比才智重要是錯的,尤其是在高科技業。每一個產業及行業的變化速度太快了,這造成你要招募的職務角色也持續在改變;昨天的機件到了明天就過時了,在如此不斷孌化的環境下,招募專才很可能會適得其反。專才往往帶著固有成見來解決問題,但這個問題就是衍生自他擅長的那個專門知識與技術,而且需要新專門技術的新型解決方法也會讓專才覺得是威脅。聰明的通才不會有成見,所以會放開心胸地去探究廣泛的解決方法,並傾向找出最好的一個。</p>
<hr>
<p>第 140 页<br>
尋找學習型動物有時是個挑戰。羅森柏格一貫使用的方法是請應徴者反省一個過去的缺失,2000 年代初期,他慣問應徴者:「你還記得 1996 年時的什麼網際網路大趨勢?你當時做對了什麽?做錯了什麽?」這是一個暗藏機關的問題,它讓應徵者去定義自己的期待,將這個期待與他們當時觀察到的事和探索出的啟示做連結,然後迫使他們去承認錯誤,不是那種「我最大的弱點在於我是個完美主義者」之類蹩腳的說詞。這是一個不可能捏造回答的問題。<br>
你可以根據近期的任何大事件來修改這個提問,這個問題的目的不是要看這個人有沒有優異的先見之明,而是要看他如何推論思考,如何從錯誤中學習。很少人能把這個問題回答得很好,但那些回答得不錯的人,有相當高的可能性是學習型動物。當然,他們可能會告訴你:「我沒什麼特殊才能,我只是有熾烈熱忱的好奇心( passionately curious)罷了!」這是愛因斯坦說的話,我們會立刻錄用他(儘管他用了「熱忱」這個字眼,他提出了相對論,有這張王牌就不必計較這一點了)。</p>
<hr>
<p>第 147 页<br>
當然啦,我們也有搞砸的時候。薩拉·卡曼加很欣賞我們的一位行銷同仁,想把這位年輕人轉入「產品襄理」計劃,不幸的是,這個計劃只收擁有電腦學位的人,這位年輕同仁沒有電腦學位。雖然,卡曼加力爭說這位年輕同仁是個自學的程式設計師,而且曾經和工程師共事過,但包括羅森柏格在內的幾名主管堅決不放大光圈,拒絕讓這位年輕同仁轉入。這位年輕的行銷部同仁凱文·希斯卓姆(Kevin Systrom)最終離開 Google,和其他人共同創辦成功的 Instagram,後來被臉書以 10 億美元收購。</p>
<hr>
<p>第 174 页<br>
給自己一項測試:如果你能解屋團隊中表現最差的 10% 成員,招募一批新人,你的組織會不會因此改善?如果會的話,那麼你必須檢靚你當初錄用這些表現差的人員時的招募流程,謀求改進。再來一個測試:你的團隊裡有沒有這樣的成員,如果他們說要離職,你不會努力留住他們?如果有的話那麽你或許該讓他們離去。</p>
<hr>
<p>第 176 页<br>
在商業界,尤其是高科技業,光是在你目前所做的事情上很傑出是不夠的,你必須追上至少一波大浪,乘著它一路向岸邊衝。很多人剛踏出校門找工作時,往往把公司擺在第一位,接著考慮職務,之後才考慮產業。其實在規劃職業生涯時,這種考慮順序是錯的。應該考量的第一順位是選擇正確產業,因為在你的職業生涯很可能會換幾次公司,但換產業就困難得多了。你應該把產業視為衝浪地點(在北加州最棒的衝浪地點是 Mavericks),把公司視為你要追的浪,你首先應該選擇有最大、最棒波浪的衝浪地點。</p>
<hr>
<p>第 179 页<br>
以下是規劃職業生涯的一些簡單步驟:<br>
思考 5 年後你希望從事的理想工作,你希望在哪裡工作?你想做什麼?希望賺多少錢?敘述這個職務:如果你在網路上看到這個工作機會,徵才內容會是什麼?現在,快轉到 4、5 年後,假設你在做這份工作,你這 5 年間的履歷表內容是什麼模樣?從現在起,你經過哪些途徑,到達那個時候的理想工作?<br>
持續想著這份理想工作,根據它來評估你目前的長處與缺點,你需要做出哪些改進?這一步需要外人提供的意見,因此和你的經理或同儕談談,徵詢他們的意見。最後,你要如何獲得這份理想工作?你需要哪些訓練?需要什麼工作經驗?<br>
順便一提的是,如果你的結論是目前的工作就是理想工作,那代表你想得不夠遠大,再重做一次,思考一份遠大對你具有挑戰性、但不是貪心的理想工作。<br>
依循這些步驟應該會有用。如果你不依循這些步驟來規劃你的職業生涯,你很可能會證明美國職棒知名捕手暨教練尤吉·貝拉( Yogi berra)說的話:「如果你不知道自己要往何處去,就得當心了,因為你很可能無法到達那裡。」</p>
<hr>
<p>第 187 页<br>
2009年12月,我們得知 Google 遭到駭客攻擊。Google 遭攻擊並不是什麼不尋常的事,事實上這種事幾乎天天都有。不過這次不同,攻擊的複雜程度前所未見,攻擊的目的也是。某個罪犯(或很可能的是一群罪犯)找到方法進入 Google 的伺服器。在此之前,絕大多數攻擊我們的壞傢伙是要破壞 Google 的服務,令我們停擺,或是令使用者更難連到我們的網站。但這一次,這些壤傢伙想竊取 Google 的機密資訊。<br>
布林立即著手攔阻攻擊,追查罪犯與他們的入侵方法。他在幾小時內召集所能找到最精明的電腦安全性專家,組成一支團隊,他們在靠近 Google 總部的一棟單調建築物内聚集起來。接下來幾星期,這個團隊建立起一套系統,可以觀看攻擊行動過程,他們看到的情形令人不寒而慄。這些駭客不僅竊取智慧財產,還試圖進入 Gmail 帳戶,包括人權人士的帳戶。這些駭客來自全球經濟成長最快速的一個國家:中國。</p>
<hr>
<p>第 210 页<br>
【每場會議都需要主人】<br>
会议應該有一位決策者或主人。<br>
決策者應該親自做事。<br>
縱使不是決策會議,例如資訊交流會議或解決方案腦力激盪會議,也應該有一位明確的會議主人。<br>
會議不像政府機構,不必要的會議不需要開。<br>
會議規模應該控制在容易運作的範圍內。<br>
出席會議並不是身分重要性的象徵。<br>
守時很重要。<br>
出席會議時,請專注在會議上。</p>
<hr>
<p>第 232 页<br>
由佩吉和布林主持的這個每週全員會議必定有一段百無禁忌的問題與回答,但隨著公司規模成長,會議這部分變得愈來愈難管理。於是,我們發展一個名為「多莉」(Dory)的系統,(以電影《海底總動員》〔 Finding Nemo〕裡患有短暫失憶症的藍色帝王魚多莉來命名,但為何用這個名字,因為我們和多莉樣,忘了!)不能或不想親自詢問問題的員工可以把問題提交到多莉系統上,其他人可以投票表達這是不是一個好問題。一個問題獲得支持的票數愈高,排名就愈高,一些較艱難的問題往往獲得很多支持。在至員會議上,員工在多莉系統裡提出的問題被顯示在螢幕上,佩吉和布林不能挑選他們想回答哪些問題,他們必須依照得票數高低順序逐一回答,不分問題的難易程度。多莉系統讓人人可以直接向執行長及團隊提出最艱難的問題,其眾包(crowdsourcing)的性質會使蹩腳問題減至最少。至於問題回答得好不好,就以比較低科技的形式來判決:全員會議的與會者持有紅色和綠色牌子,如果他們覺得一個問題沒有獲得充分回答,他們可以舉起紅色牌子。</p>
<hr>
<p>第 252 页<br>
亨利·季辛吉(Heny Kissinger)在 1969 年擔任美國國家安全顧問時提到:「我們向來言明,我們沒有永遠的敵人,而且我們會根據其他國家的行動來評判它們,而非根據它們的意識型態來評判它們,包括共產主義國家,確切地說,就是像共產主義中國這樣的國家。」在他祕密造訪中國後不到兩年,中國和美國便重啟外交關係,這是自二次大戰結束後,兩國首度建交。</p>
<hr>
<p>第 273 页<br>
2004年,羅森柏格和 Google 同事傑夫·胡柏(Jef Huber)帶布林去造訪一家小型新創公司 Keyhole,胡柏是羅森柏格在 Excitet@Home 雇用的第一位產品經理,後來加入 Google 的廣告團隊,成為首席工程師。Keyhole 的共同創辦人布萊恩·麥克蘭登( Brian McClendon)是羅森柏格和胡柏在 Excite@Home 的同事,Keyhole已經開發出一些很酷的地圖視覺與互動方式,布林立刻決定 Google應該買下這家公司。<br>
幾星期後,布林把這項收購案提呈給董事會核准,當董事們詢問他,公司要如何靠這項技術賺錢時,他的回答很簡單:「我讓羅森柏格來回答這個問題,他是生意人。」羅森柏格一直輕輕鬆鬆地觀看布林的簡報,也從未思考過買下 Keyhole 之後如何使 Google 賺錢(已經加入 Google 兩年的羅森柏格,此時正在暢飲 Google Kool-Aid 飲料機的飲料)。被布林點名後,羅森柏格說出一些說完就忘記的回答胡亂應付,之後就忘了。事實是,我們根本不知道買下 Keyhole 對 Google 的獲利有何助益。<br>
董事會決定信賴布林的判斷,讓他進行這樁收購案。大約 8 個月後,以 Keyhole 的技術為基礎的 Google 地球( Google Earth)問市,立刻大受使用者的喜愛,也為公司創造數百萬美元的收入。這個應用程式沒有廣告收入,又是免費使用,哪來的收入呢?在推出這項產品後不久,我們的一位智慧創做者山達·皮恰心想,那些下載及安裝 Google 地球應用程式的人可能也會對 Google 工具列(Google Toolbar)感興趣。工具列是簡單實用的程式,會整合進瀏覽器,為使用者提供許多有趣的功能,其中一項功能是一個小小的 Google 搜尋方框,一直掛在瀏覽器的介面上。 Google 工具列的使用者可以直接在小方框上執行 Google 搜尋,不需要進入 Google.com 網站,這往往使他們執行更多的搜尋,點選更多廣告,進而創造更多廣告收入。皮恰的構想遭到一些反對,但在烏爾斯·霍澤的推促下,這個構想快速付諸執行。</p>
<hr>
<p>第 291 页<br>
保羅·布海認為可以發展出好更多的電子郵件系統,於是展開一項取名為「馴鹿」( Caribou)的 20% 時間計劃。後來,他認為這項新產品(現在稱為 Gmail,已有數億用戶)應該可以創造收入,於是建議根據電子郵件內容,在旁邊張貼廣告。我們起初不同意,要他只管專注在把 Gmail 打造得很出色就行了,至於營收,以後再來傷腦筋。<br>
但是,Gmail 是布海的小孩,他不理會我們的意見。他駭入公司内部系統,和 AdWords 關鍵字廣告伺服器交談(Gmail + AdWords = 結合性創新)。某天早上,我們上班後發現,我們的電子郵件旁邊張貼了廣告。一開始大家很生氣,但不久,我們開始注意到,這些廣告其實還滿有用的。當時羅森柏格正好透過電子郵件和兄弟姊妹討論要為父母結婚 50 週年紀念日買禮物,他的 Gmail 信件旁邊出現高級居家用品零售商威廉索諾瑪(Williams-Sonoma)的廣告。羅森柏格的妹妹提到媽媽喜愛園藝,這個廣告建議可以買個放在庭院的長椅,羅森柏格便向他的兄弟姊妹提議這個構想,結果不僅父母獲得了一份好禮物,大家還稱讚羅森柏格很細心、考慮周到呢!(其實羅森柏格根本不是這樣的人!)<br>
幾個月後, Gmail 問市,它的廣告並沒有創造很多收入,但布海發展出來的「廣告搭配電子郵件」技術後來被用來改善我們的 AdSense 出版内容廣告產品;如今,這項產品每年創造數十億美元營收。不用說,布海並未因為他的一意孤行而受到處罰。</p>
<hr>
<p>第 326 页<br>
英國在 1865 年通過「機動車法」(Locomotive Acts),規定汽車在行駛時,前面必須有一個步行者揮舞紅色旗子,向騎馬者示警有個新玩意兒(汽車)要開來了。此法還規定這些「路上的機動車」在城鎮中行駛的速限為時速 3.2 公里,在鄉間的速限為時速 6.4 公里。該法在 1896 年被廢止。</p>
<hr>
<p>以上摘自:<br>
<img src="https://img3.doubanio.com/lpic/s27874405.jpg" alt="《Google模式》"><br>
<a href="https://book.douban.com/subject/26236445/">《Google模式》</a><br>
副标题: 挑戰瘋狂變化世界的經營思維與工作邏輯 <br>
原作名: How Google Works <br>
作者: Eric Schmidt / Jonathan Rosenberg <br>
译者: 李芳齡 <br>
出版社:天下雜誌出版社
ISBN: 9789862419724</p>
《读者》读书笔记
https://acuario.xyz/others/readers-clip/
2023-09-27T18:25:39+00:00
2017-09-01T22:39:34+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>可是,足球又总能在最黑暗的时刻振奋人心。纳粹德军占领乌克兰的时候,曾经逼迫基辅迪纳摩的球员和希特勒的卫队来一场友谊赛。赛前他们收到警告:“如果你们敢赢,就死定了。”于是一开始“在恐惧与饥饿的折磨下,他们只好准备输球。不过到了最后,他们无法抗拒尊严的呼召”。球赛结束,十一位球员穿着队衣在悬崖边上被处死。 直到今天,他们的纪念碑还是乌克兰人民的圣地。</p>
<hr>
<p>为了教大家爱护榕树这种华南最常见、最特别的树种,詹教授写了这本《细说榕树》。虽不是学术专著,但果然是细说,大长我等香港人的见识。不嫌你耻笑,也是看了这本书,我才知道菩提原来也是一种榕树,而榕树结的果实居然就是无花果!准确地说,无花果和我们常见的榕树同是榕属植物。榕的学名是 Ficus,正是无花果的拉丁文叫法。</p>……
<p>可是,足球又总能在最黑暗的时刻振奋人心。纳粹德军占领乌克兰的时候,曾经逼迫基辅迪纳摩的球员和希特勒的卫队来一场友谊赛。赛前他们收到警告:“如果你们敢赢,就死定了。”于是一开始“在恐惧与饥饿的折磨下,他们只好准备输球。不过到了最后,他们无法抗拒尊严的呼召”。球赛结束,十一位球员穿着队衣在悬崖边上被处死。 直到今天,他们的纪念碑还是乌克兰人民的圣地。</p>
<hr>
<p>为了教大家爱护榕树这种华南最常见、最特别的树种,詹教授写了这本《细说榕树》。虽不是学术专著,但果然是细说,大长我等香港人的见识。不嫌你耻笑,也是看了这本书,我才知道菩提原来也是一种榕树,而榕树结的果实居然就是无花果!准确地说,无花果和我们常见的榕树同是榕属植物。榕的学名是 Ficus,正是无花果的拉丁文叫法。</p>
<hr>
<p>在传统的想象里头,城市总是光明璀璨的,而且依据常识,都市化总是意味着更美好的生活方式。但这些未来城市却完全不是这回事,它们是一种贫富差距极大化的“贫民窟城市”。少数富人住在市中心隔离的社区,而包围它们的则是一望无际的廉价住宅和临时搭建的克难楼房。一方面,大批的农村移民将以城市无法消化的速度迅速涌进;另一方面,再也负担不起市中心昂贵生活成本的原居民则被大量迁出。 于是一种前人所不知的“中间城市”(in-between city)诞生了,那是种拥有城市人口密度但没有传统城市基建和结构的空间,住在那里的居民挤得像城市人但却保存了农村的生活方式。在传统的城市与农村之间,出现了第三种人类聚居的形态。迈克·戴维斯不是未来学家,他的推测全部建立在权威机构的统计数字和已经存在的实例之上。他最常用的例子之一就是中国,这点我们不该意外,你去任何一个县城看看,都能发现“中间城市”(或者用我们的话讲:城乡结合部)的影踪,甚至正要以光鲜面目迎接奥运和世博的北京与上海,它们的边陲难道不是未来的征兆吗?经济学常识告诉我们,农村人口朝都市进发是正常的,因为他们都想要更好的生活。在马尼拉的有毒垃圾山中搜寻可以变卖的废物,在喀土穆的街上闲逛确实要比留在农村好,因为种地是活不下去了,你再怎么种也种不过欧美的农场。不过当这些农民来到城市的门口,就会发现城市对他们并不友善,因为他们的数量和速度令城市恐惧,而城市的价格也不是他们的价格。所以他们只好困在中间,创造未来世界的主流——贫民窟城市,等待属于他们的传记。</p>
<hr>
<p>《论道歉》从心理学和精神病学的角度,分别研究了道歉的治疗效果,道歉及不道歉的理由,以及形态更复杂的道歉,比如说一个国家对另一个国家的道歉,又比如说一个世代为另一个世代犯下的错误道歉。牵涉整个国族的道歉是复杂的,因为谁有权去代表一个国家向他人致歉谢罪呢?政府的领导人一定就是最恰当的人选吗?牵涉前人过错的道歉也是复杂的,因为这一代人为什么要为他们没犯过的罪去寻求原谅呢?凭什么祖先的罪业可以加在后人身上?对于后面这个问题,拉扎尔的解释倒也简单:如果一个人会为了国家和祖先骄傲,会为了他不认识的国家足球队员亢奋,会为了与他无关的历史英雄自豪,他又有什么理由不去连带地分担羞耻与罪疚?道歉一旦涉及国与国,就还得考虑不同国家的语言文化,因为有怎么样的文化就有怎么样的道歉观。拉扎尔指出,日文大概是道歉语言最丰富的一种语言,它每种认错的方式都与致歉者和致歉对象相关,对象的身份不同说抱款的用语也不同。这表示日本式的道歉着眼于关系的安置多于情感的坦白,所以日式道歉总有一些修饰语使得致歉者处于卑下顺从的位置。或者,这是日本很难对中国说抱歉的原因,拉扎尔猜测。</p>
<hr>
<p>而且吹水要比说谎还糟。说谎的人虽然违心地作出虚假的陈述,但他起码还晓得真相是什么,心里头有真假是非的判断,因此才有说谎的可能。在这个意义上,一个骗子还算尊重真实的价值。吹水的人可不同了,他根本不在乎事实,不关心真假,纯纯粹粹就是为了应付场面而吹,甚至为吹而吹。这个吹水的时代很像苏格拉底在世时的雅典,每个人都以为自已很有知识,对什么事情都有想法,既自由且民主,结果全是游谈无根,自己都不知道自已在说什么。</p>
<hr>
<p>薛爱华还总结了一条规律,但凡国力强盛的时代,其绘画中表现出来的外国人就愈是正常客观,甚至文明优越,唐朝就是如此。相比之下,一向被认为很柔弱的宋朝呢,则喜欢强调蛮夷的粗俗低劣。</p>
<hr>
<p>即便一生多不如意,回顾起来,兰姆还是要说:“过去的不顺心之事,我不断地纷纷然重新经历一番。往日的挫折我不再受他们伤害,像是穿上了盔甲……在我一生中所发生过的各种各样的倒霉事,如今我一件也不想取消。”(《除夕随想》)</p>
<hr>
<p>例如查尔斯·兰姆(Charles Lamb),就像王念青先生对他说过的:“‘别着急,他说,‘闲时慢慢读,慢慢学,图的只是心中供养一点清气!’”(《英国首相的礼物》)年纪大了以后,“不必做研究不必求学问真好。买书玩赏装帧,读书为了消遣,写作不计毁誉,这样美丽的颓废,人老了才有缘消受”。明明有无数的价码,明明有那么多书市上买卖的遭遇,但金钱在此,已经不是诱惑和诱惑的障碍,而是记忆池塘上悬垂的无钩鱼丝,不为垂钓,只为标记。书是划算,还是昂贵,都不再重要了。</p>
<hr>
<p>有些东西可以忘记,例如雨伞;有些事丢不了,但最好忘记。亨利在失物招领处结识了一个从俄罗斯巴什喀尔地区来的数学教授,成为好友,西格弗里德伦茨透过这段友谊写出记忆与遗忘更宏大的一面。现在的德国已离纳粹时代甚远,大家都忘了种族主义和仇恨政治的肆虐,但那真是一段不该被遗忘的记忆,因为只要忘了它,它就会自己回来,变形以另一番面目重现。这是记忆的吊诡,只有记住悲剧,它才不会重演。</p>
<hr>
<p>说是文学,但宇文所安由回忆这一个视点出发,却穿越了中国文化的各种元素和面向,例如中国各大名山上的碑铭石刻。西方人不作兴搞这套,而是喜欢保留自然风光的原始风貌。但中国文人除了想把自己对山水的感观留在山水之中,与后人分享之外,还想透过刻在石上的文字表示自己也曾到此一游。这是中国人企盼不朽的方式,他们想被后人记住。一想到人生在世最终灰飞烟灭,难免叫人悲从中来。“前不见古人,后不见来者”是这么一种面对时间变幻席卷一切的力量时感到的寂寞,难怪就会“念天地之悠悠,独怆然而涕下”。所以这么多碑记记的也是昔人往事,因为念及古人就这么一代代消散在今人的记忆之中,就会感到有责任要把他们的名字事迹留给后世。前人的永在,全靠吾辈的追念。而我们这一整代的人,终究也会整代消失。有意思的,是写怀古文章、收集古代器物与勒石刻碑此等怀旧行为,却把自己也都留在后人的记忆中了。上泰山,看见这么多古代文士王公的痕迹,那可是一代代中国人抗拒朽坏和遗忘的悲凉记录。</p>
<hr>
<p>身份是一个很重要的标志。因为有固定的身份,岗位就是确认了,就能够具体通过这个身份而进行回馈,说得老套一点,就是为社会出一份力。然后就是回家的时候了。原来出门不是放弃责任,而是要更明白地寻找与确认自己的责任。</p>
<hr>
<p>至于杂文,论者喜欢强调王小波的“自由精神”,说鼓励大家独立思考,千万别盲从圣人教化一言堂,宁可当“一只特立独行的猪”,也不要做被人运动起来的无脑大众。对生长在大陆的年轻人来说,他的言论真是醍醐灌顶,有解政治遗毒的奇效。不过坦白讲,像我这种自小看胡适长大的港台同胞,就不觉得王小波有多惊人了。所以他说的很多话在我看来就像太阳总在东边升起一样,的确是真理,但也用不着跳出浴缸大喊一声“Eureka”! 千万别误会,我对王小波没有半分不敬,恰恰相反,我觉得今天的读者还是应该继续读他的作品。“我们这个社会里的论战大多要从平等的讨论转为一方对另一方的批判,这是因讨论的方式决定的。根据我的观察,这些讨论里不是争谁对谁错,而是争谁好谁坏。一旦争出了结果,一方的好人身份既定,另一方是坏蛋就昭然若揭。好人方对坏蛋方当然还有些话要说,不但要批判,还要揭发。”(《论战与道德》)很不幸,这些道理如今仍然管用,尤其适合网上那批一谈日本问题就上升到揭发汉奸,一碰民主改革就要捍卫民族利益,上纲上线的速度比搭直升机还快的热血青年。</p>
<hr>
<p>其实吉尔兹自己也明白,完全理解异文化是不可能的。在《地方知识》(Local Knowledge)这部论文集里,吉尔兹坦白告诉我们人类学家没有神奇的能力,不可能把自己完全变成某个部族的巫师,再回过头来用很精确的语言去向自己的同族描述那个部族的世界观。我们很难变成另一种人,然后再找出不同的人群有哪些共同的地方。事实上,吉尔兹根本怀疑任何超文化原则与普遍社会规律的存在。我们只能在异文化之间来回跳跃,既远且近。但是,只要我们也学会用一种遥远的距离和新鲜的眼光看自己,我们就会明白自己不是唯一。</p>
<hr>
<p>而文化的作用,吉尔兹在其经典《文化的诠释》(The Interpretation of Caltures)里有个很直接的说法:“它把意义加诸世界,使得世界可以被理解。”那么文化又是什么呢?“它是一套承袭而来的要领构成的系统,这个系统以象征的形式表达出来。人类透过这套象征系统可以沟通、保持和发展关于生命的态度与知识。”人类学家要做的就是去把不同文化的象征系统解读出来,使大家可以认识不同的文化。</p>
<hr>
<p>凡是一个真正动摇了人类思考方式的思想家,总会叫人摇头或者发笑。其实董启章没说错,有些动物脏就脏在它的位置不对,不只是物理的空间位置,而且是抽象范畴中的位置。玛丽·道格拉斯成名作《洁净与危险》(Purity and Danger:An Analysis of the Concepts of Pollution and Taboo)中最有名的例子就是一种动物:猪。她分析《圣经》把猪列为不洁之物的原因,说那是因为猪虽然和牛羊一样长了蹄,但又不像一般有蹄动物那样反刍。换句话说,在当时近东地区居民的世界观里,有蹄动物都该是会反刍的,而猪却违反了这个常规,既不能完整地纳入有蹄动物的类别,也不能和其他不反刍同时又无蹄的动物并列。所以猪是不洁的异类,乃禁食之物。 玛丽·道格拉斯又发展出她对禁忌的看法,指出禁忌总是不洁的、恶心的,因为它们破坏了世界分类的常规,是种混沌模糊的异物。所以研究一个文化的禁忌,看它怎样定义肮脏与污染,就是在反向地分析它分类万物和认识世界的方法。曾经弄得香港闹哄哄的种种禁忌争论亦可作如是观。例如乱伦,什么叫作乱伦?为什么有的社会禁止表兄妹相爱,有的却不?人兽交又为何是种违反自然的禁忌?难道不是因为我们很“自然”地把人和动物分成截然不同的东西吗?所以人狗交合绝对不行,但拿马和驴配出骡子却是可以的。</p>
<hr>
<p>正如“女工关怀”的成员,香港科技大学的潘毅教授在导言里所说,这二十多年来从“工人”到“打工妹”的转变是惊人的。工人阶级在过去是社会主义国家的主人,地位崇高,打工妹的“打工”则意味着身份变成了为“资本主义老板”工作的工人。这里的“妹”字更是复杂,因为这是个性别身份。于是一个打工妹既被困在一个随时可以被解雇、经常受到压榨的打工处境,同时又是个试图改变自己女性地位的主体,为了抗拒逼婚与传统农村的家务劳动而外出。 《失语者的呼声》使我明白打工妹固然失语,但是仍有呼声。她们在城乡的差距之间,在经济的变化之中,在我们媒体提供的世界里产生了欲望。这种欲望会叫她们碰到残酷的现实,但也是一种抗争的动力:从前是抗争农村生活里的性别分工,将来就是抗争劳动关系里的压迫与不公。</p>
<hr>
<p>2006 年的诺贝尔文学奖也是在政治争议声中诞生的。因为土耳其的帕穆克(Orhan Pamuk)前一年 2 月才在瑞士对记者说,“在 20 世纪对亚美尼亚人和库尔德人的种族屠杀事件上,奥斯曼土耳其帝国有罪。三万人和一百万人惨遭杀害”,于是被他的老乡告上法庭,罪名是土耳其刑法第三〇一条的“亵渎土耳其国格及其政府”。按照这条法例的规定,如果被告是在国外发表有关言论,则罪加一等,最高可判入狱三年。关于后面这点,我们中国人都明白,这叫作“去外面唱衰自己人”,十分严重。</p>
<hr>
<p>比下议院更妙的就是“唐宁街十号”了,很多人都说这是全世界最出名的地址,但问题是它为何是个“地址”呢?想想看,白宫、中南海、凡尔赛宫、克里姆林宫……全世界有哪一个大国的领导人官邸是有地址的呢?就算有,肯定也都被这个宫那个府的响亮名号遮住了。只有英国首相办公居住的地方不叫首相府,却以地址著称,活似个民宅。 为了解开这个疑惑,我把英国历史学家塞尔登(Anhony Seldon)的《唐宁街十号》(10 Downing Street )由头到尾读了一遍。虽然找不到明确的答案,但起码有点眉目了。 原来这座房子是18世纪的乔治二世送给“首席财政大臣”罗伯特·沃波尔的礼物,但罗伯特·沃波尔开出了条件,说他不能以私人名义接受唐宁街上的这幢房产,除非将它保留给日后所有当上首席财政大臣的人。所谓“首席财政大臣”其实就是后来的首相,自此之后,唐宁街十号就成了内阁首辅的官邸。直到今天,它大门上最显眼的东西除了那个十号门牌之外,就是一小块刻着“首席财政大臣”字样的铜板了。</p>
<hr>
<p>一个老外开书局,我们当然会联想起在上海卖日文书的内山书店。西尔维娅·比奇替乔伊斯出了《尤利西斯》,内山完造也帮鲁迅出版了不少东西,乔伊斯把莎士比亚书店当办公室,鲁迅也用内山书店来会客。一部英文小说要在巴黎出版,是因为当时的英语世界太封闭,鲁迅的中文作品要在上海这个半殖民地面世,而且得靠一个日本友人协助,则是那年头中国政治情势的悲剧。保守的英语世界把自己的天才赶到了巴黎,比较新潮的日本却用它的出版品引来一群求知若渴的中国知识分子。如果有人把这两家几乎同代的书店放在一起,为它们写一个既平行又相异的故事,那该有多好看呀。</p>
<hr>
<p>藏书是生活的另一面相,书话是读书和觅书的历程,二者同样漫长,但藏书终必散尽,留下的是一则又一则书话。</p>
<hr>
<p>今天人人都谈文化创意产业,觉得这真是个点石成金的好买卖,只要有一点不知打哪里来的创意,就能变出天文数字般的财富。于是大家都忘了,所谓文化产业,本质其实只不过是非常土气、非常卑微的手工业罢了。许多大型时装品牌都会推出一些设计一般、大量生产的镜框,加上个商标,就突然变身为名牌高档货了。不过讲究眼镜的人都晓得,在眼镜的世界里,真正站在顶峰的其实是些传统得不能再传统的手工小作坊。例如日本的泰八郎,不开分号,不加入连锁集团,不假手于外包工厂,就他一个老头每天在那里磨胶版,一年只做不过千副眼镜,卖完就算。香港是有很多顾客排队下订金,但香港绝不会有人想做泰八郎。</p>
<hr>
<p>陆灏这本集子也是他的读书札札记,记的都是他读到的有趣故事。例如其中一篇提到一类喜欢欢毁书的读书人(专有名词叫biblioclast),佼佼者是达尔文,喜欢把一本厚书撕成两半,放进外套上的两个口袋,“认为这样方便携带”。大诗人华兹华斯要是进了朋友的书房,“就好像把狗熊放进了郁金香花园,会用一把满是牛油的刀,裁开一本伯克的著作,以致书中每一页都留下油渍”。同是诗家,雪莱的行动就诗意多了,喜欢折纸船,每见池塘,必从书中撕下几页折成小船下水,看它们浮游徜徉。</p>
<hr>
<p>每一个人的藏书都是他暂时淤塞的浅滩汐湖,终有流出冲散的一天,终有回到大河海潮的一刻,本来就非我所有。那些注定没有流传价值的,就活该蒸发,回归大气。所以无意义的书,不妨尽成废纸,且还有再用的价值,堪比器官捐赠。</p>
<hr>
<p>木心《同情中断录》的序言,就只是短短一句触目惊心的话:“本集十篇,皆为悼文,我曾见的生命,都只是行过,无所谓完成。”其实书亦何尝不是如此,我曾拥有、曾读过的书,在我的生命中都只是行过而已。行过,走了,无所谓完成,亦无所谓终结。</p>
<hr>
<p>经典绝非有限的水池,而是大海,每游出一尺,你就发现前面还有一尺,无穷无尽,足可在不知不觉间溺死那些不懂疲倦的好奇读者。怕累,或许也是不读经典的理由,但比起怕累,我们一般更怕死。所以还是读书好,起码读着读着便不知老之将至了。</p>
<hr>
<p>关于经典的最经典定义是——那些没有人看但人人都在谈的书。我觉得这个明显是嘲讽的说法其实隐约说出了真相,经典确实是用来让人说事的,而说它也确实比读它更重要。道理很简单,就看看我们身边的人吧,有谁不知道什么叫“三顾茅庐”?有谁不明白“桃园三结义”?但在 21 世纪的第八年,还有多少人真正读过《三国演义》这部通俗又畅销的名著呢?我很怀疑。尽管如此,我们却还是乐此不疲地引用那些典出《三国演义》的故事和段子,甚至把它们浓缩成四字成语,用它们形容看见的事,以它们表达心里的想法,仿佛人人都读过三国,都通晓里头的内容似的。</p>
<hr>
<p>好在我是那种书迷,就是自己没有的东西固然想要,若是人家得了也不妒忌,反而替别人高兴,觉得自己喜欢的事物有同好欣赏,吾道果然不孤。</p>
<hr>
<p>今天我们坐在电脑荧幕之前,手握“老鼠”,上下推移,并以指尖点压,虽是前所未见的阅读动作,但那屏幕画面的移动概念却兜了个圈回到古代,文字成为一篇连续体,而非可以断开的页面。一篇文章看到一半若想回头翻查,就得往前卷动,英文叫作“scrolling”,正是罗马人阅读卷轴的动作。</p>
<hr>
<p>书之于人,就和食物音乐一样,必要但是日常,不足为奇也不足称道。</p>
<hr>
<p>我们的习惯是什么?那就是把书看得格外崇高而神圣,认为读书是一种很离世、很出尘的行为。因此为了让它回到人间,让它有点烟火味,就得不时出动大家都认得的名人推介好书,甚至集合一大批小孩集体朗诵(最好能有破世界纪录的人数),好叫电视台看看我们都正在读书呢。劝人读书,介绍好书,我们一概统称为“推动”阅读风气,仿佛不推, 它就动不起来了。</p>
<hr>
<p>研究印刷史和书籍史的学者们有个共识,认为古登堡印刷术的发明,是人类两种阅读取向的分水岭。在印刷术普及之前,读者追求的是“精读”(intensive reading),犹如古人注经,务求一字一句都要看出个道理,往往一本书能耗上一辈子的生命。原因简单,那时流通的书数量极少,一个罗马时代的学者要是能在一生之中读过三百本书,就是惊人的硕学鸿儒了。等到印刷术出现,书籍的复制方便了,短短百年之间,无论种类还是数量都有几何级数的增长。这时的学者如果只看过三百本书还敢对人夸称自己博学,肯定遭人耻笑。所以印刷术的年代是个“泛读”(extensive reading )为王的时代,读书首要是求多求广,速度自然也得跟得上。</p>
<hr>
<p>成长,就是一个不断发现自己被欺骗的残酷醒觉历程。想当年,我也有过纯情的日子,曾经十分羡慕法国人民的文化素质高,不只电影晓得安排主角去法兰西学院听列维·施特劳斯讲课,就连福柯最深奥难懂的《词与物》也成了地铁里人手一册的畅销书。直到上了大学,有学长传授“书皮学”(book cover studies),我才恍然大悟,法国人有可能是世界上最懂得在知识上伪装、在文化上炫耀的一帮家伙。</p>
<hr>
<p>经过这许多年,我现在算不算是一个正常的读者呢?这么讲吧,我开始能够体会浮士德的悲剧,也开始明白知识、禁果与傲慢的关联了,你愈是以为自己谦卑低下,就愈容易犯上骄傲的罪,愈容易陷入文字障所导致的我慢。</p>
<hr>
<p>以上摘自:
<img src="https://img3.doubanio.com/lpic/s28703990.jpg" alt="《读者》"><br>
<a href="https://book.douban.com/subject/26773392/">《读者》</a><br>
作者:梁文道<br>
出版社:文化艺术出版社</p>
《哥伦比亚的倒影》读书笔记
https://acuario.xyz/others/reflection-of-Colombia-clip/
2023-09-27T18:25:39+00:00
2017-08-14T00:02:27+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>昔鲁迅将“海派”与“京派”作了对比:精当处颇多阐发,然则这样的南北之分刚柔之别,未免小看小言了海派。海派是大的,是上海的都市性格,先地灵而人杰,后人杰而地灵;上海是暴起的,早熟的,英气勃勃的,其俊爽豪迈可与世界各大都会格争雄长;但上海所缺的是一无文化渊源,二无上流社会,故在诱胁之下,嗒然面颜尽失,再回头,历史契机寢寢而过。</p>
<hr>
<p>面子第一要紧,上海人讲究穿着为来为去为了“面子”,因此服装的含义或可三而述之:一、虚荣;二、爱好;三、自尊——凡虚荣每含欺骗性,是达到目的前的手段,故属权术的范畴。凡爱好,虽说发乎天性,而外向效应也是取悦人引诱人,内向效应则形成优越感,自恋自宠,乐此不疲。凡自尊,为了确保身份,成全个人的存在证觉,伦理观念流于生活细节,细节累计为大节——虚荣心态蔚为社会风尚,这个无处不在的大魔障,个人没法冲破,服装的欺骗性便愈转愈烈。而爱好的心态呢,或先认衣衫后认人,或既认衣衫又认人,近乎中庸,其实模棱两可,衣可人可。自己也只要做个“可人”。那第三类所谓伦理观念细节化的,是精于“衣道”者,细认衣衫细认人。能从“衣衫”上辨别判断“人”,必要时,达到不认衣衫只认人的明哲度——从前的上海人,在“衣”与“人”之关系的推论上,也许总不外乎这样的吧,因为后来上海人就不虚荣了,继之不爱好了,终于不自尊了,再后来又想虚荣又想爱好又想自尊,已不知如何个虚荣爱好自尊法。所以,从前的上海人在“衣”与“人”之广义关系的考辨推论上,总不外乎,就是这样的吧。</p>……
<p>昔鲁迅将“海派”与“京派”作了对比:精当处颇多阐发,然则这样的南北之分刚柔之别,未免小看小言了海派。海派是大的,是上海的都市性格,先地灵而人杰,后人杰而地灵;上海是暴起的,早熟的,英气勃勃的,其俊爽豪迈可与世界各大都会格争雄长;但上海所缺的是一无文化渊源,二无上流社会,故在诱胁之下,嗒然面颜尽失,再回头,历史契机寢寢而过。</p>
<hr>
<p>面子第一要紧,上海人讲究穿着为来为去为了“面子”,因此服装的含义或可三而述之:一、虚荣;二、爱好;三、自尊——凡虚荣每含欺骗性,是达到目的前的手段,故属权术的范畴。凡爱好,虽说发乎天性,而外向效应也是取悦人引诱人,内向效应则形成优越感,自恋自宠,乐此不疲。凡自尊,为了确保身份,成全个人的存在证觉,伦理观念流于生活细节,细节累计为大节——虚荣心态蔚为社会风尚,这个无处不在的大魔障,个人没法冲破,服装的欺骗性便愈转愈烈。而爱好的心态呢,或先认衣衫后认人,或既认衣衫又认人,近乎中庸,其实模棱两可,衣可人可。自己也只要做个“可人”。那第三类所谓伦理观念细节化的,是精于“衣道”者,细认衣衫细认人。能从“衣衫”上辨别判断“人”,必要时,达到不认衣衫只认人的明哲度——从前的上海人,在“衣”与“人”之关系的推论上,也许总不外乎这样的吧,因为后来上海人就不虚荣了,继之不爱好了,终于不自尊了,再后来又想虚荣又想爱好又想自尊,已不知如何个虚荣爱好自尊法。所以,从前的上海人在“衣”与“人”之广义关系的考辨推论上,总不外乎,就是这样的吧。</p>
<hr>
<p>从前的上海人中做吃食生意者,利用顾客心理,各有拿手好戏。每年鸡蛋旺季,冷藏设备有限,急需把鸡蛋推销掉,你去喝豆浆吧,刚刚坐下,伙计过来问: “甜格咸格?” 你说了,他说: “好,咸浆,鸡蛋一只还是两只?” 你说一只,他喊道: “喂——又来咸浆一碗,加只蛋。” 你原是只想喝咸豆浆的,如果他问“要勿要加鸡蛋”,你会答“勿要”,而他问“鸡蛋一只还是两只你便去考虑两只太多,一只就够了——上海人这点偷换概念的小伎俩,施之于外省来的旅客,可谓稳扎稳打,除非是本地的“人精”,就不甘于被摆布: “喔,老先生,侬早,请坐,甜浆咸浆?” “咸格。” “好,咸浆,鸡蛋一只两只?” “今朝勿要哉。” “哪能拉?” “昨日被侬噱进了。” “啊哟哟,侬老人家真是,鸡蛋吃勒侬肚皮里格,又勿是请我吃,侬钞票麦卡麦卡,豆腐浆里勿摆蛋赛过八月半唔没月亮,阿是?好,侬阿要辣油?” “我是相信吃辣格!” “好,嗳——咸浆一碗重辣,鸡蛋拣新鲜大点格,马上就来!” “概念再次偷换——上海人擅长在饮食男女等细节上展施小伎俩,多半总是收效的,因之自我感觉个个光滑良好,如鱼得水的水其实都是鱼,然而却就此优哉游哉逝者如斯夫。即使轮到整个大都会被偷换了大概念,上海人还是以为靠微型的概念偷换,便足与巨型的概念偷换相周旋相抗衡,似乎愈是绝处愈能逢生,而且夹缝里发了财。租界期如此,孤岛期如此,日据沦陷期如此,胜利光复期如此,如此这般期如此,直到永远。</p>
<hr>
<p>上海人是不怕玩物丧志的,猪大肠叫“圈子”,鸡肫肝称“时件”,青鱼肉脏曰“秃肺”,狗脔讳“香肉”:蛙腿号“樱桃”,鱼尾则“豁水”,那中段者“肚裆”;火腿与鲜猪爪共炖,文火历昼夜,红白相映,赐谧“金银蹄”,形容黄鱼炸得蓬松,乃名“松鼠黄鱼”,嫌“鳖”不韵,改字“圆鱼”,或“甲鱼”、“水鸡”,其沿背壳之软体,昵呼“裙边”,美食家之大嗜也,再要溯涉“松江四鳃鲈鱼”,矜贵若翻螂嫖食谱,那就更加如梦似真了。</p>
<hr>
<p>京菜——源出山东,以鲜嫩香脆为特色,倚仗宫廷款目,煞有富贵介事,引人想入非非,而调理纯正,盘式雍容,菜中之缙绅也。 粤菜——有“海派广东菜”之称,淡雅清爽,于若生若熟中见技巧,品名花俏,用料淫奇,神妙处处大有仙趣,菜中之丽姝也。 川菜——标榜“七味”:酸、甜、麻、辣、苦、香、咸。“八滋”:麻辣、鱼香、酸辣、怪味、红油、干煸等;实则一辣以蔽之,自有其王气霸气,菜中之纵横家也; 扬菜——镇江世系,刀工精,主料明,和顺适口回味醰悠。可家常,可盛宴,菜中之出将入相者也。再者,维扬细点,允为隽物。 本帮菜——本帮菜就是上海人伶俐性格的食品化,小东门十六铺德兴馆:红烧秃肺、生炒圈子、酱魚樱桃、虾子乌参,尤其是一道以生煸草头垫底的蒜蓉红焖大肠,遐迩闻名。广西路老正兴:白糟腌青鱼、春笋火腿川槽,得味自然,他家的糟是自己酿制的。小花园大陆饭店的清炒去皮鳝背,松腴芳茹,而炸双排不拘挂糖醋、洒椒盐,一色金黄勿沾油。牛庄路天香楼:象牙菩鱼,刺少肉致,配葱蒜姜酒下锅生炒,白里透黄,宛如象牙,那菩鱼是杭州七里塘所产,确系神品——上海菜刁钻精乖,识时务者为俊杰也。</p>
<hr>
<p>夜戏散场,压轴性的喧嚣闹忙过后,上海整个疲乏不堪,到处油污脏水废物垃圾。长长的多桥的苏州河秽黑得无有倒影,蒸发着酷烈的辛臭。野猫在街口哀鸣。窗子一扇扇熄了。马路上的夜风说冷不冷说热不热,含着都市统体的汗骚膻腥,淡而分明。真的能感觉到屋顶路面都在喘息。暗暗讨饶,只剩街灯下碎烂的报纸飘起、旋落。 等到江海关的大钟一敲,晨光一照,报童一喊,垃圾车一过,商店的千门万户一开,上海又上了海,精神一小时一小时抖擞起来。</p>
<hr>
<p>大约廿世纪二十年代初到四十年代末,上海显现了畸形的繁华,过来之人津津乐道,道及自身的风流韵事,别家的鬼蜮伎俩——好一个不义而富且贵的大都会,营营扰扰颠倒昼夜。豪奢泼辣刁钻精乖的海派进化论者,以为软红十丈适者生存,上海这笔厚黑糊涂账神鬼难清。讵料星移物换很快就收拾殆尽,魂销骨蚀龙藏虎卧的上海过去了,哪些本是活该的,哪些本不是活该的;谁说得中肯,中什么肯,说中了肯又有谁听?因为,过去了呀。</p>
<hr>
<p>倘若谁来说,这些屋子,全没人住,也不能反证他是在哄我,因为是下午,晚上窗子有灯光,便觉得里面有人,如果孤居的老妇死了,灯亮着,死之前非熄灯不可吗,她早已无力熄灯,这样,每夜窗子明着,明三年五年,老妇不可怜,那灯可怜,幸亏物无知,否则世界更逼促紊乱,幸亏生活在无知之物的中间,有隐蔽之处,回旋之地,憩息之所,落落大方地躲躲闪闪,一代代蹙眉窃笑到今天。</p>
<hr>
<p>任何事物,当它失去第一重意义时,便有第二重意义显出来,时常觉得是第二重意义更容易由我靠近,与我适合,犹如墓碑上倚着辆童车,热面包压着三页遗嘱,以致晴美的下午也就此散步在第二重意义中而俨然迷路了,我别无逸乐,每当稍有逸乐,哀愁争先而起,哀愁是什么呢,要是知诺哀愁是什么,就不哀愁了——生活是什么呢,生活是这样的,有些事情还没有做,一定要做的……另有些事做了,没有做好。</p>
<hr>
<p>如果我端坐着的岸称之为此岸,那么望见的岸称之为彼岸(反之亦然),这里是纳蕤思们芳踪不到之处,凡是神秘的象征的那些主义和主义者都已在彼岸的轮廓丛中,此岸空无所有,唯我有体温兼呼吸,今天会发生什么事,白昼比黑夜还静(一定要发生什么事了)空气煦润凉爽,空气也凝定不动,渐渐我没有体温没有呼吸,没有心和肺,没手也没足(如果感到有牙齿,必是痛,如果觉得有耳朵,那是虚鸣)我健康正常,所以什么都没有,目不转睛,直视已着对岸参差重叠的轮廓前后凹凸地耸峙在蓝天下……要发生的事发生了——对岸什么都没有,整片蓝天直落地平线,匀净无痕,近地平线绀蓝化为淡紫,地是灰绿,岸是青绿,河水里,前前后后参参差差凹凹凸凸重重叠叠的倒影清晰如故,凝定如故,像一幅倒挂的广毯——人类历代文化的倒影……前人的文化与生命同在,与生命相渗透的文化已随生命的消失而消失,我们仅是得到了它们的倒影,如果我转过身来,分开双腿,然后弯腰低头眺望河水,水中的映象便俨然是正相了——这又何能持久,我总得直起身来,满脸赧颜羞色地接受这宿命的倒影,我也并非全然悲观,如果不满怀希望,那么满怀什么呢……起风了,河面波灏粼粼,倒影潋滟而碎,这样的溶溶漾漾也许更显得澶漫悦目——如果风再大,就什么都看不清了。</p>
<hr>
<p>人的伤感情调无不可厌,物的伤感情调却普遍可爱。</p>
<hr>
<p>我的大甥在“哈佛”攻文学,问他的指导教授:美国文明究竟是什么文明?教授说:“山洞文明。”真正的智者都躲在高楼大厦的“山洞”里,外面是人欲横流的物质洪水——大甥认为这个见解绝妙,我亦以为然。 当我刚迁入此六十一街三十W.APT时,也颇有山顶洞人之感。看门大员力拒野兽,我便可无为而治。储藏食品的橱柜特多,冰箱特大,我的备粮的本能使我一次出猎,大批带回,塞满橱柜冰箱,一个月是无论如何吃不完的,这岂非更像原始人的冬令蛰伏——是文明生活的返祖现象。想想觉得很有趣,再想想又觉得我自己不是智者,而且单身索居,这山洞委实寂静得可怕,几个星期不下楼不出门,偶然飘来一封信,也燃不起一堆火。山洞文明不好受。</p>
<hr>
<p>我就是受苦吃亏在老是要想到什么是应该的,什么是不应该的。</p>
<hr>
<p>“隐私”,“自然生活”,昆德拉乐谈的一而二、二而一的话题,“任何揭人隐私的行为都该受到鞭挞”。谁来鞭挞呢?“隐私”原本不成其为“权利”,当它受到邻人般的警探和警探般的邻人昼夜作践时,“隐私”才反证为神圣。因此,一旦到了争隐私的时候,必是万难拥有隐私了。而专以摧残隐私为能事、乐事者,却看准被虐者的弱点,久而久之的作践,使人丧失私生活的界范,再久而久之就泯灭了私生活的意识。</p>
<hr>
<p>昆德拉毕竟经历过来,他看清幼稚无知是青年的宿命特征,黑白分明的道德观加上罗曼蒂克的情绪爆炸力,正好被极权的恐怖统治者充分利用,一代青年老去,另一代青年上来:……极权主义没有年龄,就这样,总归是没有年龄的东西支配有年龄的东西。</p>
<hr>
<p>人们在俯首听令时,甘于殉从最简明易行的令,宗教早就试验了这类庶民的心理取向。贯彻一种酷烈的意志,以采用几个字、两三句烙印鲜明的话最能生效,最富诱惑力。初受政治教条的控制时,哗嚣折腾中,来不及联想到人的极权乃是神的极权的变相和加剧,等到有所察觉,人的极权的机械器械系统性的完备程度,早已超出神的极权的模式之上了。</p>
<hr>
<p>有个捷克人,申请移民签证,官员问: “你打算到哪里去?” “哪儿都行。” 官员给了他一个地球仪: “自己挑吧!” 他看了看,慢慢转了转,对官员道 “你还有没有别的地球仪?” ——Milan Kundera
2017年03月15日 12时53分
渡江的轮船上站满了人,我挤到船头,倚栏迎风——是我的谬见,常以为人是一个容器,盛着快乐,盛着悲哀。但人不是容器,人是导管,快乐流过,悲哀流过,导管只是导管。各种快乐悲哀流过流过,一直到死,导管才空了。疯子,就是导管的淤塞和破裂。 …… 容易悲哀的人容易快乐,也就容易存活。管壁增厚的人,快乐也慢,悲哀也慢。淤塞的导管会破裂。真正构成世界的是像蓝衣黑伞人那样的许许多多畅通无阻的导管。如果我也能在啜泣长叹之后把伞挥得如此轻松曼妙,那就好了。否则我总是自绝于这个由他们构成的世界之外—他们是渺小,我是连渺小也称不上</p>
<hr>
<p>话说人际关系,唯一可爱的是“映照”,映照印证,以致日月光华,旦复旦兮,彪炳了一部华夏文化史。滔滔泛泛间,“魏晋风度”宁是最令人三唱九叹的了;所谓雄汉盛唐,不免臭脏之讥;六朝旧事,但寒烟衰草凝绿而已;韩愈李白,何足与竹林中人论气节。宋元以还,艺文人士大抵骨头都软了,软之又软,虽具须眉,个个柔若无骨,是故一部华夏文化史,唯魏晋高士列传至今掷地犹作金石声,投江不与水东流,固然多的是巧累于智俊伤其道的千古憾事,而世上每件值得频频回首的壮举,又有哪一件不是憾事。</p>
<hr>
<p>美貌是一种表情。 别的表情等待反应,例如悲哀等待怜悯,威严等待慑服,滑稽等待嬉笑。唯美貌无为,无目的,使人没有特定的反应义务的挂念,就不由自主地被吸引,其实是被感动。 其实美貌这个表情的意思,就是爱。 这个意思既蕴藉又坦率地随时呈现出来。 拥有美貌的人并没有这个意思,而美貌是这个意思。</p>
<hr>
<p>人害怕寂寞,害怕到无耻的程度。换言之,人的某些无耻的行径是由于害怕寂寞而作出来的。就文句而言,还是“人害怕寂寞,害怕到无耻的程度”这样比较清通。</p>
<hr>
<p>莫干山的竹林,高接浮云,密得不能进去踱步。使我诧异的是竹林里极为干净,终年无人打扫,却像日日有人洁除;为什么,什么意思呢,神圣之感在我心中升起……继而淡然惋惜了——那山上的居民,山下来的商客,为的是吃笋,买卖笋干,箬叶可制鞋底,斫伐以筑屋搭棚,劈削而做种种篾器,当竹子值钱时,功能即奴性。生活,是安于人的奴性和物的奴性的交织。更有画竹,咏竹,用竹为担,为篙,为斗械,为刑具——都已必不可少,都已可笑,都已寂寞。</p>
<hr>
<p>另外(难免有一些另外),中国人既温暾又酷烈,有不可思议的耐性,能与任何祸福作无尽之周旋。在心上,不在话下,十年如此,百年不过是十个十年,忽然已是千年了。苦闷逼使“人”有所象征,因而与自然作无止境的亲嫟,乃至熟昵而狡黠作狎了。至少可先例两则谐趣:金鱼、菊花。自然中只有鲋、鲫,不知花了多少代人的宝贵而不值钱的光阴,培育出婀娜多姿的水中仙侣,化畸形病态为固定遗传,金鱼的品种叹为观止而源源不止。野菊是很单调的,也被嫁接、控制、盆栽而笼络,作纷繁的形色幻变。菊花展览会是菊的时装表演,尤其是想入非非的题名,巧妙得可耻——金鱼和菊花,是人的意志取代了自然的意志,是人对自然行使了催眠术。中庸而趋极的中国人的耐性和猾癖一至于此。亟待更新的事物却千年不易,不劳费心的行当干了一件又一桩,苦闷的象征从未制胜苦闷之由来,叫人看不下去地看下,看下去。“自然”在金鱼、菊花这类小节上任人摆布,在阡陌交错的大节上,如果用“白发三千丈”的作诗方法来对待庄稼,就注定以颗粒无收告终,否则就不成其为“自然”了。</p>
<hr>
<p>“自然”对于“人”在理论上、观念上若有误解曲解,都毫不在乎。野果成全了果园,大河肥沃了大地,牛羊入栏,五粮丰登,然后群莺乱飞,而且幽阶一夜苔生——历史短促的国族,即使是由衷的欢哀,总嫌浮佻庸肤,毕竟没有经识过多少盛世凶年,多少钧天齐乐的庆典、薄海同悲的殇礼,尤其不是朝朝暮暮在无数细节上甘苦与共休戚相关,即使那里天有时地有利人也和合,而山川草木总嫌寡情乏灵,那里的人是人,自然是自然,彼此尚未涵融尚未钟毓……海外有春风芳草,深宵的犬吠,秋的丹枫,随之绵衍到煎鱼的油香,邻家婴儿的夜啼,广式苏式月饼。大家都自言自语:不是这样,不是这样的。心里的感喟:那些都是错了似的。因为不能说“错了的春风,错了的芳草”,所以只能说不尽然、不完全……异邦的春风旁若无人地吹,芳草漫不经心地绿,猎犬未知何故地吠,枫叶大事挥霍地红,煎鱼的油一片汪洋,邻家的婴啼似同隔世,月饼的馅儿是百科全书派……就是不符,不符心坎里的古华夏今中国的观念、概念、私心杂念……乡愁,去国之离忧,是这样悄然中来、氤氲不散。</p>
<hr>
<p>以上摘自:
<img src="https://img3.doubanio.com/lpic/s4531886.jpg" alt="《哥伦比亚的倒影》"><br>
<a href="https://book.douban.com/subject/5355829/">《哥伦比亚的倒影》</a><br>
作者:木心<br>
出版社:广西师范大学出版社</p>
RegEx折腾之路(一)
https://acuario.xyz/posts/regex-tricks-1/
2023-09-27T18:25:39+00:00
2017-04-28T00:00:33+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>关于 RegEx,一直记得一句话:</p>
<blockquote>
<p>好的 RegEx 是短而精的。</p>
</blockquote>
<p>近来在研究 RegEx 的折腾之路上走来走去。决定把自己所遇到的一些小例子记下来。
一方面方便自己回顾、反思,另一方面给大家参考、指正。
想起前段时间工作上遇到的一个 situation。</p>……
<p>关于 RegEx,一直记得一句话:</p>
<blockquote>
<p>好的 RegEx 是短而精的。</p>
</blockquote>
<p>近来在研究 RegEx 的折腾之路上走来走去。决定把自己所遇到的一些小例子记下来。
一方面方便自己回顾、反思,另一方面给大家参考、指正。
想起前段时间工作上遇到的一个 situation。</p>
<p>源文本如下:</p>
<pre tabindex="0"><code>(通用,单选,非必填)BRAND||常规品牌
(通用,单选,非必填)DESIGNER||设计师品牌
(通用,多选,非必填)MATERIAL||面料(1)
(通用,多选,非必填)MATERIAL||面料(2)
(特定,多选,非必填)NECKLINE||领口
(特定,多选,非必填)SLEEVE LENGTH||袖长
(特定,多选,非必填)SLEEVE TYPE||袖型
(特定,多选,非必填)WAISTLINE||腰线
(特定,多选,非必填)DRESS LENGTH||裙长(1)
(特定,多选,非必填)DRESS LENGTH||裙长(2)
(特定,多选,非必填)FIT||体型
(特定,多选,非必填)OCCASION||场合(1)
(特定,多选,非必填)OCCASION||场合(2)
(特定,多选,非必填)STYLE||款式(1)
(特定,多选,非必填)STYLE||款式(2)
(特定,多选,非必填)ACCENT||特色(1)
(特定,多选,非必填)ACCENT||特色(2)
(特定,多选,非必填)ACCENT||特色(3)
</code></pre><p>需要匹配出每一行中对应的中、英文标题:
如英文标题「SLEEVE LENGTH」,及对应的中文标题「袖长」
如英文标题「DRESS LENGTH」,及对应的中文标题「裙长」</p>
<p>乍一看很简单,但是实际做起来却没有那么容易。写出的 RegEx 总会受到行末的序号所影响。最后使用两个 RegEx 分情况进行匹配:</p>
<ul>
<li>使用下式匹配无序号的情况:</li>
</ul>
<pre tabindex="0"><code>(?:\))(.+)(?:\|\|)(.+(?:[^\uFF09\s]$))
</code></pre><p>例如能够匹配出 <code>DESIGNER 设计师品牌</code>, <code>FIT 体型</code></p>
<ul>
<li>使用下式匹配有序号的情况:</li>
</ul>
<pre tabindex="0"><code>(?:\))(.+)(?:\|\|)(.+)(?:\s*\uFF08)
</code></pre><p>例如能够匹配出 <code>MATERIAL 面料</code>, <code>STYLE 款式</code></p>
<p>然后使用或关系进行合并:</p>
<pre tabindex="0"><code>(?:\))(.+)(?:\|\|)(?:(.+(?:[^\uFF09\s]$))|(.+)(?:\s*\uFF08))
</code></pre><p>匹配结果如下图:
<img src="https://ooo.0o0.ooo/2017/04/27/590213c8359e1.png" alt=""></p>
<p>这段正则的释意如下:</p>
<pre tabindex="0"><code>(?:\)) #分组但不捕获「非必填」后面的右括号
(.+) #分组1匹配任意内容(即英文)
(?:\|\|) #分组但不捕获双竖线
(?: #分组但不捕获
(.+ #分组2匹配任意内容(即无序号中文)
(?:[^\uFF09\s]$) #分组但不捕获空白符和右括号外的字符
) #分组2结束
| #分组或关系
(.+) #分组3匹配任意内容(即有序号中文)
(?:\s*\uFF08) #分组但不捕获空白符和左括号
) #分组结束
</code></pre><p><img src="https://ooo.0o0.ooo/2017/04/27/590213c83591a.png" alt=""></p>
<p>一直没有想到什么好的解决办法能够在一个简短的正则表达式中完美实现这一个需求。如果读者有什么好想法(好吧其实并没什么读者)请评论分享你的 idea。</p>
<hr>
<p>2017.6.22 更新</p>
<p>感谢 Inoreader 读者 <a href="http://www.inoreader.com/u/icery">Andy</a> 的评论和建议,其提供的 RegEx 如下:</p>
<pre tabindex="0"><code>(?:\))([^\)]+)\|\|([^\s\uFF09\n]+)
</code></pre><p>释意如下:</p>
<pre tabindex="0"><code>(?:\)) #分组但不捕获「非必填」后面的右括号
([^\)]+) #分组捕获除右括号之外的内容
\|\| #双竖线
([^\s\uFF09\n]+) #分组捕获除空白符、右括号和换行符外的字符
</code></pre><p><img src="https://ooo.0o0.ooo/2017/06/22/594b68f251ea7.png" alt=""></p>
<p>更近一步精简的版本如下:</p>
<pre tabindex="0"><code>([^\)]+)\|\|([^\s\uFF09\n]+)
</code></pre><p>释意如下:</p>
<pre tabindex="0"><code>([^\)]+) #分组捕获除右括号之外的内容
\|\| #双竖线
([^\s\uFF09\n]+) #分组捕获除空白符、右括号和换行符外的字符
</code></pre><p><img src="https://ooo.0o0.ooo/2017/06/22/594b68f22a636.png" alt=""></p>
<hr>
<p><strong>总结</strong></p>
<pre tabindex="0"><code>(?:\))(.+)(?:\|\|)(?:(.+(?:[^\uFF09\s]$))|(.+)(?:\s*\uFF08))
(?:\))([^\)]+)\|\|([^\s\uFF09\n]+)
([^\)]+)\|\|([^\s\uFF09\n]+)
</code></pre><p>对比上文的三个 RegEx,可以总结出编写 RegEx 的些许技巧:</p>
<ol>
<li>匹配时有正向和反向两种思路,不一定要写出完整匹配目标文本的特定 RegEx,而可以选择使用排除法进行优化。(如「[1-8]」匹配数字 1-8,,亦可写为「[^90]」匹配除 9 和 0 外的字符)</li>
<li>「分组不捕获」无需滥用,如果只提取分组内的内容,则无关未分组内容也无需使用「分组不捕获」,以精简 RegEx。(如本文中的双竖线其实是无需使用分组不捕获的)</li>
<li><strong>好的 RegEx 是短而精的。</strong></li>
</ol>
《精通正则表达式》学习笔记(一)
https://acuario.xyz/posts/mastering-regex-summary-1/
2023-09-27T18:25:39+00:00
2017-04-18T00:29:18+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="ch1-正则表达式入门">Ch.1 正则表达式入门</h2>
<h3 id="正则表达式介绍">正则表达式介绍</h3>
<ul>
<li>正则表达式(Regular Expression)是经过专门编写的文本字符串,用来匹配字符串(尤其是文件内字符串)集合中符合该模式的所有字符串。RegEx 能够添加、删除、分离、叠加、插入和修整各种类型的文本和数据。</li>
<li>完整的正则表达式由两种字符构成:
<ol>
<li>特殊字符(如 *),称为 <strong>元字符</strong>(metacharacters)</li>
<li>其他字符为称为 <strong>文字</strong>(literal),或是普通文本字符(normal text characters)</li>
</ol>
</li>
<li>写正则表达式时,我们需要在对欲检索文本的了解程度与检索精确性之间求得平衡。针对某个检索文本,正则表达式基本不可能匹配不期望的结果,使用它就是合理的。</li>
</ul>……
<ul>
<li><a href="https://acuario.xyz/mastering-regex-summary-1/">《精通正则表达式》学习笔记(一)</a>
Ch.1 正则表达式入门
Ch.2 入门示例拓展</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-2/">《精通正则表达式》学习笔记(二)</a>
Ch.3 正则表达式的特性和流派概览</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-3/">《精通正则表达式》学习笔记(三)</a>
Ch.4 表达式的匹配原理</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-4/">《精通正则表达式》学习笔记(四)</a>
Ch.5 正则表达式实用技巧</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-5/">《精通正则表达式》学习笔记(五)</a>
Ch.6 打造高效正则表达式</li>
<li><a href="https://acuario.xyz/mastering-regex-summary-6/">《精通正则表达式》学习笔记(六)</a>
Ch.10 PHP 相关的正则表达式</li>
</ul>
<hr>
<h2 id="ch1-正则表达式入门">Ch.1 正则表达式入门</h2>
<h3 id="正则表达式介绍">正则表达式介绍</h3>
<ul>
<li>正则表达式(Regular Expression)是经过专门编写的文本字符串,用来匹配字符串(尤其是文件内字符串)集合中符合该模式的所有字符串。RegEx 能够添加、删除、分离、叠加、插入和修整各种类型的文本和数据。</li>
<li>完整的正则表达式由两种字符构成:
<ol>
<li>特殊字符(如 *),称为 <strong>元字符</strong>(metacharacters)</li>
<li>其他字符为称为 <strong>文字</strong>(literal),或是普通文本字符(normal text characters)</li>
</ol>
</li>
<li>写正则表达式时,我们需要在对欲检索文本的了解程度与检索精确性之间求得平衡。针对某个检索文本,正则表达式基本不可能匹配不期望的结果,使用它就是合理的。</li>
</ul>
<h3 id="regex-语法基础">RegEx 语法基础</h3>
<p><img src="https://ooo.0o0.ooo/2017/04/17/58f4bbe62a242.png" alt="元字符总结"></p>
<ul>
<li>只有在字符组内部,连字符 <code>-</code> 才用来表示范围。</li>
<li>只有在字符组内部(且在字符组首位),脱字符 <code>^</code> 才作为一个元字符。</li>
<li>只有在在字符组外部,脱字符 <code>^</code> 用来表示一个行锚点(line anchor)</li>
<li>只有在在字符组外部,点号 <code>.</code> 才作为一个元字符。</li>
<li><code>[^x]</code> 的含义不是「只有当这个位置不是 x 时才能匹配」,而是「匹配一个不等于 x 的字符」。前者含义可以匹配空行,后者不可。</li>
</ul>
<h2 id="ch2-入门示例拓展">Ch.2 入门示例拓展</h2>
<h3 id="prel-语法基础">Prel 语法基础</h3>
<ul>
<li>Perl 表达式及运行参数</li>
</ul>
<table>
<thead>
<tr>
<th>字符</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>=~</code></td>
<td>连接 RegEx 和待搜索的目标字符串</td>
</tr>
<tr>
<td><code>=</code></td>
<td>运算符,变量赋值</td>
</tr>
<tr>
<td><code>==</code></td>
<td>运算符,测试两个数值是否相等</td>
</tr>
<tr>
<td><code>-p</code></td>
<td>表示对目标文件的每一行进行查找和替换</td>
</tr>
<tr>
<td><code>-i</code></td>
<td>表示整个程序接在命令后面</td>
</tr>
<tr>
<td><code>-e</code></td>
<td>表示将替换结果写回文件</td>
</tr>
<tr>
<td><code>-w</code></td>
<td>表示严格检查语法并显示警告</td>
</tr>
</tbody>
</table>
<pre><code>举个栗子,下面的 Perl 程序用于将所有 sysread 替换为 read。
```
% perl -p -i -e -w 's/sysread/read/g' file
```
</code></pre>
<h3 id="prel-中-regex-的使用">Prel 中 RegEx 的使用</h3>
<ul>
<li>
<p>Perl 语句说明</p>
<ol>
<li><code>$var =~ m/regex/</code> 将判断一个正则表达式是否能匹配某个字符串。
<code>m</code> 表示匹配(match),斜线用来标注正则表达式的边界(其本身不属于正则表达式)。整个测试语句作为一个单元,返回 true 或 false 值。类似的,</li>
<li><code>$var =~ s/regex/replacement/</code> 将使用一个正则表达式来匹配并替换某个字符串。
<code>s</code> 表示替换(substitution,也叫查找和替换(search and replace))。</li>
<li><code>$var =~ qr/regex/</code> 将一个正则表达式生成为一个“regex 对象(regex object)”,作为变量保存,供后续使用。</li>
</ol>
<p>举个栗子:</p>
<pre tabindex="0"><code>$reply =~ m/^[0-9]+$/
$reply =~ s/Jeff/Jeffrey/
</code></pre></li>
<li>
<p>Perl 的模式修饰符
模式修饰符,跟在表示结尾的斜线之后的参数。</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>字符</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/i</code></td>
<td>表示此测试不区分大小写(ignore)</td>
</tr>
<tr>
<td><code>/g</code></td>
<td>表示全局匹配(global match/replacement)</td>
</tr>
<tr>
<td><code>/m</code></td>
<td>表示允许使用增强的行锚点(emhanced line anchor),可将 <code>^</code> 和 <code>$</code> 从字符串模式切换到逻辑行模式,即以逻辑换行进行锚位匹配。</td>
</tr>
<tr>
<td><code>/x</code></td>
<td>表示宽松排列的表达式(free-form expressions),可用于多行正则表达式增强可读性</td>
</tr>
</tbody>
</table>
<p>举个栗子:</p>
<pre tabindex="0"><code>$reply =~ m/^[0-9]+$/i
$reply =~ m/^[0-9]+$/g
$reply =~ m/^[0-9]+$/x
</code></pre><h3 id="regex-语法基础-1">RegEx 语法基础</h3>
<h4 id="正则匹配符">正则匹配符</h4>
<table>
<thead>
<tr>
<th>字符</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>\t</code></td>
<td>制表符</td>
</tr>
<tr>
<td><code>\n</code></td>
<td>换行符</td>
</tr>
<tr>
<td><code>\r</code></td>
<td>回车符</td>
</tr>
<tr>
<td><code>\s</code></td>
<td>任何 <code>空白</code> 字符(如空格符、制表符、进纸符等)</td>
</tr>
<tr>
<td><code>\S</code></td>
<td>除 <code>\s</code> 之外的任何字符</td>
</tr>
<tr>
<td><code>\w</code></td>
<td><code>[a-zA-Z0-9]</code>(在 <code>\w+</code> 中很有用,可以用来匹配一个单词)</td>
</tr>
<tr>
<td><code>\W</code></td>
<td>除 <code>\w</code> 之外的任何字符</td>
</tr>
<tr>
<td><code>\d</code></td>
<td><code>[0-9]</code>,即数字</td>
</tr>
<tr>
<td><code>\D</code></td>
<td>除 <code>\d</code> 之外的任何字符</td>
</tr>
<tr>
<td><code>^</code></td>
<td>行起始锚位符</td>
</tr>
<tr>
<td><code>$</code></td>
<td>行结束锚位符</td>
</tr>
</tbody>
</table>
<p>ps.<code>^$</code> 可用来匹配空行,因为空行的行起始和行结束是相连的。</p>
<h4 id="分组">分组</h4>
<p>使用 <code>(…)</code> 用来分组并捕获,使用 <code>(?:…)</code> 来分组但不捕获。
<strong>捕获顺序按照括号出现的先后顺序依次进行</strong>,而非内外顺序。
<img src="https://i.loli.net/2019/06/18/5d08395268c0328493.jpg" alt="捕获型括号">
<img src="https://i.loli.net/2019/06/18/5d0839526882d45916.jpg" alt="嵌套型括号"></p>
<ul>
<li>思考</li>
</ul>
<ol>
<li><code>$var =~ s/\bJeff\b/Jeff/i</code>
上述 Perl 表达式中 <code>i</code> 仅对所有匹配的字符串生效,对 replacement 的文本没有影响。即匹配所有 jeff、Jeff、jEFF……替换为 Jeff。</li>
<li><code>$price =~ s/(\.\d\d[1-9]?)\d*/$1/</code>
上述 Perl 表达式将数字文本格式化为保留两位小数,且如果第三位非零则保留第三位。即 12.375000000564 => 12.375,12.375 => 12.375,37.5000 => 37.50。</li>
</ol>
<h4 id="环视">环视</h4>
<p>环视结构不匹配任何字符,只匹配文本中的<strong>特定位置</strong>,类似单词分界符 <code>\b</code>,锚点 <code>^</code> 和 <code>$</code>。
环视结构的主体为要求的文本,而非匹配的文本,即使用环视时,环视结构内的文本将不会被匹配,而是作为标记文本位置的特殊语法进行使用。</p>
<table>
<thead>
<tr>
<th>字符</th>
<th>名称</th>
<th>别名</th>
<th>作用</th>
<th>条件</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>(?:…)</code></td>
<td>非捕获型分组</td>
<td></td>
<td>分组但不捕获</td>
<td></td>
</tr>
<tr>
<td><code>(?=…)</code></td>
<td>肯定顺序环视</td>
<td>正前瞻</td>
<td>环视文本后的文本是否为要求文本</td>
<td>子表达式能够匹配右侧文本</td>
</tr>
<tr>
<td><code>(?!…)</code></td>
<td>否定顺序环视</td>
<td>反前瞻</td>
<td>环视文本后的文本是否非要求文本</td>
<td>子表达式不能匹配右侧文本</td>
</tr>
<tr>
<td><code>(?<=…)</code></td>
<td>肯定逆序环视</td>
<td>正后顾</td>
<td>环视文本前的文本是否为要求文本</td>
<td>子表达式能够匹配左侧文本</td>
</tr>
<tr>
<td><code>(?<!…)</code></td>
<td>否定逆序环视</td>
<td>反后顾</td>
<td>环视文本前的文本是否非要求文本</td>
<td>子表达式不能匹配左侧文本</td>
</tr>
</tbody>
</table>
<p>环视在检查子表达式能否匹配的过程中,其本身不会 <code>占用</code> 任何文本。
e.g.匹配文本为 <strong><code>Jeffrey</code></strong>,使用如下 RegEx 时匹配结果不同:</p>
<pre tabindex="0"><code>Jeffrey #匹配 Jeffrey
(?=Jeffrey)Jeff #定位 Jeffrey 中 Jeff 和 rey 的中间位置,匹配 Jeffrey 中的 Jeff
Jeff(?=rey) #与上式等价
\bJeff(?=s\b) #定位 Jeffs 中 Jeff 和 s 的中间位置,匹配 Jeffs 中的 Jeff
(?<=\bJeff)(?=s\b) #定位 Jeffs 中 Jeff 和 s 的中间位置,且并未匹配任何内容
</code></pre><p><img src="https://ooo.0o0.ooo/2016/11/22/5833c2a23571a.png" alt="(?=Jeffrey)Jeff的匹配">
<code>(?=Jeffrey)Jeff</code> 的匹配</p>
<p><img src="https://ooo.0o0.ooo/2016/11/22/5833c2a234c2a.png" alt="\bJeff(?=s\b)的匹配">
<code>\bJeff(?=s\b)</code> 的匹配</p>
<p><img src="https://ooo.0o0.ooo/2016/11/22/5833c2a23bf20.png" alt="(?<=\bJeff)(Jeff的匹配">
<code>(?<=\bJeff)(?=s\b)</code> 的匹配</p>
<ul>
<li>思考
如何使用 Perl 表达式将数字文本格式化为右起三位数逗号分隔的数字。即 375000000564 => 375,000,000,564?</li>
</ul>
<ol>
<li>
<p><code>$var =~ s/(?<=\d)(?=(\d\d\d)+$)/,/g;</code>
<code>(?<=\d)</code> 表示左侧必须有数字,方式出现 ,375,000,000,564
<code>(?=(\d\d\d)+$)</code> 表示从最右方进行肯定逆序环视(正后顾),每看到三个数字进行一次环视标记。</p>
</li>
<li>
<p><code>$var =~ s/(\d)(?=(\d\d\d)+$)/$1,/g;</code>
<code>(\d)</code> 使用捕获型括号实现逗号前的内容分组,然后保持 $1 内容不变,在其后添加逗号</p>
</li>
<li>
<p><code>$var =~ s/(\d)((\d\d\d)+\b)/$1,$2/g;</code>
上式不使用环视,但无法实现期望。最终得到类似 375000000564 => 375,000000564。
<code>((\d\d\d)+\b)</code> 匹配的数字属于最终匹配文本,不能作为“未匹配的部分”,供 <code>/g</code> 的下一次匹配迭代使用。
如欲使用该式进行实现,可配合循环结构:</p>
</li>
</ol>
<pre tabindex="0"><code>while ($var =~ s/(\d)((\d\d\d)+\b)/$1,$2/g) {
#空结构体,使用条件操作
}
</code></pre><ol start="4">
<li><code>\b([a-z]+)((?:\s|<[^>]+>)+)(\1\b)</code>
上适用于匹配一段文本中连续出现的重复单词,具体示意如下图:
<img src="https://i.loli.net/2019/06/18/5d0839b053ca014873.jpg" alt="示意图"></li>
</ol>
[转]学到不会忘
https://acuario.xyz/posts/learn-to-unforgettable/
2023-09-27T18:25:39+00:00
2017-04-13T23:52:47+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>近几日重新拿起《精通正则表达式》,重读前言的时候觉得感同身受,在作者博客看到可以转载,遂转至此以自勉。</p>
<p>本文由 Yurii 原创,来源:<a href="http://www.luanxiang.org/blog/">乱象,印迹</a>
原文链接 <a href="http://www.luanxiang.org/blog/archives/1249.html">学到不会忘</a></p>
<p>原文如下</p>
<hr>
<p>博文视点的张春雨编辑告诉我,八次印刷的《精通正则表达式》已经全部售罄了, O’Reilly 与电子工业出版社续签了版权合同,准备重新上市,让我写一点东西。</p>
<p>该写什么好呢?</p>
<p>2007 年 《精通》上市时,我还在中关村,天气好的时候可以望见颐和园的佛香阁;而现在,窗外景色已经换成了珠江边的小蛮腰;对正则表达式的使用,也从随手拈来变得生疏——许多问题需要翻查《精通》,翻查自己写的《正则指引》。究其原因,与正则表达式直接相关的开发做得少了,古话说“勤则立,嬉则荒”,就是这个道理。</p>
<p>荒是荒了,毕竟还没荒废,虽然有很多细节需要查阅,但是我很清楚,某个问题能不能用正则表达式解决,该怎样解决。或者说,虽然手上生疏了,心里其实没有忘记,而这一切,归源都是之前死啃过《精通》的缘故。</p>……
<p>近几日重新拿起《精通正则表达式》,重读前言的时候觉得感同身受,在作者博客看到可以转载,遂转至此以自勉。</p>
<p>本文由 Yurii 原创,来源:<a href="http://www.luanxiang.org/blog/">乱象,印迹</a>
原文链接 <a href="http://www.luanxiang.org/blog/archives/1249.html">学到不会忘</a></p>
<p>原文如下</p>
<hr>
<p>博文视点的张春雨编辑告诉我,八次印刷的《精通正则表达式》已经全部售罄了, O’Reilly 与电子工业出版社续签了版权合同,准备重新上市,让我写一点东西。</p>
<p>该写什么好呢?</p>
<p>2007 年 《精通》上市时,我还在中关村,天气好的时候可以望见颐和园的佛香阁;而现在,窗外景色已经换成了珠江边的小蛮腰;对正则表达式的使用,也从随手拈来变得生疏——许多问题需要翻查《精通》,翻查自己写的《正则指引》。究其原因,与正则表达式直接相关的开发做得少了,古话说“勤则立,嬉则荒”,就是这个道理。</p>
<p>荒是荒了,毕竟还没荒废,虽然有很多细节需要查阅,但是我很清楚,某个问题能不能用正则表达式解决,该怎样解决。或者说,虽然手上生疏了,心里其实没有忘记,而这一切,归源都是之前死啃过《精通》的缘故。</p>
<p>在阅读《精通》之前,我已经查阅了网上的不少资料,对正则表达式有了基本了解,能像模像样地解决一些实际问题,可算“够用”了。这时候遇见《精通》这样“现实价值不那么大”的书,能静下心去阅读,其实带着点毕业不久的傻气,只是单纯想把它弄懂搞透。所以,遇到匹配原理这类看来没多少实用价值的知识,还会愿意花时间去揣摩、研习。回头想想,也正是因为当时有这种傻气,可算是意外的收获:工作中经常需要学习一些工具和原理,虽然当时也“学会”了,但不久就忘个精光;相比之下,正则表达式却是学到了“不会忘”的程度。更典型的例子是游泳,几乎人人都可以做到“一朝学会,终身不忘”。同样是“学会”,为什么差距这么大呢?</p>
<p>这个问题我想了很久,最后的答案是,“学会”的定义是不同的。</p>
<p>通常我们说“学会”了某项技术、某门语言,意思是“凑合能用”,或者说“可以对照文档( Google )解决问题”的程度——你用 Python 解决了一个问题,就说明你“学会”了Python ,哪管是步步 Google ,还是照抄现成的代码。而我们说“学会”了游泳,意思是可以在水里行动而不沉下去,更重要的是在游泳时不需要时刻背诵各种口诀:吸气—伸手—划水—蹬腿—抬头—呼气……,如果你在泳池里还要时时谨记这些口诀,是绝对谈不上“学会”的。</p>
<p>两者虽然都叫“学会”,其实相差迥异:第一种“学会”是“照猫画虎”,第二种“学会”是“融会贯通”,虽然都可以解决问题,但从第一种“学会”到达第二种“学会”,其实需要经历漫长的过程。而且,两种“学会”都能解决问题,所以在达到第二种“学会”的漫长过程中,你很可能感觉不到自己的进步,反而会困惑继续学习的意义乃至放弃——既然能对着文档操作,既然有现成的资料,为什么要去理解背后的原理呢。</p>
<p>对我来说,第二种“学会”的好处是显而易见的,最重要的一点就是不会忘记——学习的时间增长一倍,遗忘的难度将会增加十倍、二十倍甚至一百倍。这些年来,我见到了太多这样的例子:有人每次用到正则表达式都会抓狂,都要四处极力搜索、反复盲目尝试,花很长时间才能凑出、蒙对解决方案;另一方面,他们又不愿意花时间潜心学习《精通》这样的经典。因为反复遗忘,需要反复学习,最终浪费了大量的时间。</p>
<p>许多人不愿意专门花时间来学习正则表达式,是认为它属于奇技淫巧,并非工作必须。但这理由是不成立的:我们大部分人不是作家,但为了在需要的时候写得出文章,还是必须专门花时间来练习写作。而且,专门花时间来学习“非必要”的技能,以后往往能有意想不到的收获。我真切体会到并且懂得这个道理,恰好也是与《精通》的翻译有缘。</p>
<p>在翻译《精通》时,为了省却重新编排索引的麻烦,需要做到中英文版页页对应,于是我专门学习了侯捷老师写的《Word排版艺术》,并且亲手尝试了每个例子,记熟了有关的概念和术语,从此学会了格式和样式的角度定义文档,再不用为格式之类的问题烦恼。这些年来虽然用得并不 多,却没有忘记。去年写作《正则指引》时,我事先完整定义了各种格式、样式、引用等等,交稿时节省了自己和出版社大量的时间。</p>
<p>另一个例子仍然与正则表达式有关。去年,为了写作《正则指引》中Unicode的章节,我专门花了时间研读Unicode规范,虽然最终《指引》中没有列出学到的全部知识,但我对Unicode的理解已经不再限于“在程序中设定Unicode编码即可”。前几天,有位同事遇到Unicode字符Ä (U+00C4)无法打印的问题,于是我建议他使用A和¨ (U+0041和U+0308)的两个Unicode字符来表示(按照Unicode规范,两个字符可以“组合”成一个字符),果然解决了问题。这段经历再次证明,真的学会了,就真的不会忘。</p>
<p>亚里士多德曾说:所谓幸 福,就是尽情地施展我们掌握的技能,等待期望的结果。然而很多时候,我们以为自己可以解决,但是之前学过的技能已经遗忘,于是施展起来步履沉重、举步维艰,最后只能精疲力竭地等待结果,自然与幸福绝缘。相反,如果我们能把重要的技能都真正学会,学到不会忘的程度,自然可以接近幸福。如果你想收获自如驾驭 正则表达式的幸福,不妨从这本书开始吧。</p>
Nano使用教程
https://acuario.xyz/posts/how-to-use-nano/
2023-09-27T18:25:39+00:00
2017-04-06T21:52:19+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="nano-简介">Nano 简介</h2>
<p>Nano 是 Linux 上一个简单的文本编辑器,比起 Vim 来说它轻量很多,易于上手。遥想笔者第一次接触 Vim 的时候简直可怕,因为零基础,连退出都不会,直接死在 Vim 里面哈哈哈哈。Nano 就不至于这么困难了,随便看一两个命令和快捷键就能学会,远远没有 Vim 的学习曲线那样陡。虽然手册这种东西,没什么太大价值,但是自己整理一下印象深刻一些,也留备以后自己查阅。
没错我就是用来给博客凑数的!(逃</p>……
<h2 id="nano-简介">Nano 简介</h2>
<p>Nano 是 Linux 上一个简单的文本编辑器,比起 Vim 来说它轻量很多,易于上手。遥想笔者第一次接触 Vim 的时候简直可怕,因为零基础,连退出都不会,直接死在 Vim 里面哈哈哈哈。Nano 就不至于这么困难了,随便看一两个命令和快捷键就能学会,远远没有 Vim 的学习曲线那样陡。虽然手册这种东西,没什么太大价值,但是自己整理一下印象深刻一些,也留备以后自己查阅。
没错我就是用来给博客凑数的!(逃</p>
<h2 id="基本使用">基本使用</h2>
<h3 id="命令及选项">命令及选项</h3>
<ul>
<li>命令:<code>nano [选项] [[+行,列] 文件名]</code></li>
</ul>
<table>
<thead>
<tr>
<th>选项</th>
<th>GNU 长选项</th>
<th>意义</th>
</tr>
</thead>
<tbody>
<tr>
<td>-h, -?</td>
<td>--help</td>
<td>显示此信息</td>
</tr>
<tr>
<td>+行,列</td>
<td></td>
<td>从所指列数与行数开始</td>
</tr>
<tr>
<td>-A</td>
<td>--smarthome</td>
<td>启用智能 HOME 键</td>
</tr>
<tr>
<td>-B</td>
<td>--backup</td>
<td>储存既有文件的备份</td>
</tr>
<tr>
<td>-C <目录></td>
<td>--backupdir=<目录></td>
<td>用以储存独一备份文件的目录</td>
</tr>
<tr>
<td>-D</td>
<td>--boldtext</td>
<td>用粗体替代颜色反转</td>
</tr>
<tr>
<td>-E</td>
<td>--tabstospaces</td>
<td>将已输入的制表符转换为空白</td>
</tr>
<tr>
<td>-F</td>
<td>--multibuffer</td>
<td>启用多重文件缓冲区功能</td>
</tr>
<tr>
<td>-H</td>
<td>--historylog</td>
<td>记录与读取搜索/替换的历史字符串</td>
</tr>
<tr>
<td>-I</td>
<td>--ignorercfiles</td>
<td>不要参考nanorc 文件</td>
</tr>
<tr>
<td>-K</td>
<td>--rebindkeypad</td>
<td>修正数字键区按键混淆问题</td>
</tr>
<tr>
<td>-L</td>
<td>--nonewlines</td>
<td>不要将换行加到文件末端</td>
</tr>
<tr>
<td>-N</td>
<td>--noconvert</td>
<td>不要从 DOS/Mac 格式转换</td>
</tr>
<tr>
<td>-O</td>
<td>--morespace</td>
<td>编辑时多使用一行</td>
</tr>
<tr>
<td>-Q <字符串></td>
<td>--quotestr=<字符串></td>
<td>引用代表字符串</td>
</tr>
<tr>
<td>-R</td>
<td>--restricted</td>
<td>限制模式</td>
</tr>
<tr>
<td>-S</td>
<td>--smooth</td>
<td>按行滚动而不是半屏</td>
</tr>
<tr>
<td>-T <#列数></td>
<td>--tabsize=<#列数></td>
<td>设定制表符宽度为 #列数</td>
</tr>
<tr>
<td>-U</td>
<td>--quickblank</td>
<td>状态行快速闪动</td>
</tr>
<tr>
<td>-V</td>
<td>--version</td>
<td>显示版本资讯并离开</td>
</tr>
<tr>
<td>-W</td>
<td>--wordbounds</td>
<td>更正确地侦测单字边界</td>
</tr>
<tr>
<td>-Y <字符串></td>
<td>--syntax=<字符串></td>
<td>用于加亮的语法定义</td>
</tr>
<tr>
<td>-c</td>
<td>--const</td>
<td>持续显示游标位置</td>
</tr>
<tr>
<td>-d</td>
<td>--rebinddelete</td>
<td>修正退格键/删除键混淆问题</td>
</tr>
<tr>
<td>-i</td>
<td>--autoindent</td>
<td>自动缩进新行</td>
</tr>
<tr>
<td>-k</td>
<td>--cut</td>
<td>从游标剪切至行尾</td>
</tr>
<tr>
<td>-l</td>
<td>--nofollow</td>
<td>不要依照符号连结,而是覆盖</td>
</tr>
<tr>
<td>-m</td>
<td>--mouse</td>
<td>启用鼠标功能</td>
</tr>
<tr>
<td>-o <目录></td>
<td>--operatingdir=<目录></td>
<td>设定操作目录</td>
</tr>
<tr>
<td>-p</td>
<td>--preserve</td>
<td>保留XON (^Q) 和XOFF (^S) 按键</td>
</tr>
<tr>
<td>-q</td>
<td>--quiet</td>
<td>沉默忽略启动问题, 比如rc 文件错误</td>
</tr>
<tr>
<td>-r <#列数></td>
<td>--fill=<#列数></td>
<td>设定折行宽度为 #列数</td>
</tr>
<tr>
<td>-s <程序></td>
<td>--speller=<程序></td>
<td>启用替代的拼写检查程序</td>
</tr>
<tr>
<td>-t</td>
<td>--tempfile</td>
<td>离开时自动储存,不要提示</td>
</tr>
<tr>
<td>-u</td>
<td>--undo</td>
<td>允许通用撤销[试验性特性]</td>
</tr>
<tr>
<td>-v</td>
<td>--view</td>
<td>查看(只读)模式</td>
</tr>
<tr>
<td>-w</td>
<td>--nowrap</td>
<td>不要自动换行</td>
</tr>
<tr>
<td>-x</td>
<td>--nohelp</td>
<td>不要显示辅助区</td>
</tr>
<tr>
<td>-z</td>
<td>--suspend</td>
<td>启用暂停功能</td>
</tr>
<tr>
<td>-$</td>
<td>--softwrap</td>
<td>启用软换行</td>
</tr>
<tr>
<td>-a, -b, -e, -f, -g, -j</td>
<td></td>
<td>(忽略,为与Pico 相容)</td>
</tr>
</tbody>
</table>
<h3 id="快捷键">快捷键</h3>
<p><img src="https://i.loli.net/2019/06/19/5d09172af367366380.jpg" alt="Nano编辑窗口"></p>
<p>在 Nano 编辑窗口中:</p>
<ol>
<li><code>Ctrl</code> 键被表示为一个脱字符 <code>^</code>,故 <code>Ctrl+W</code> 被写成了 <code>^W</code>。</li>
<li><code>Alt</code> 键被表示为一个 <code>M</code>(从"Meta"而来),故 <code>Alt+W</code> 被写成了 <code>M-W</code>。</li>
<li>使用用方向键移动光标。</li>
</ol>
<table>
<thead>
<tr>
<th>含义</th>
<th>快捷键</th>
</tr>
</thead>
<tbody>
<tr>
<td>标记</td>
<td><code>Ctrl+6</code> / <code>Alt+A</code></td>
</tr>
<tr>
<td>复制整行</td>
<td><code>Alt+6</code></td>
</tr>
<tr>
<td>剪贴整行</td>
<td><code>Ctrl+K</code></td>
</tr>
<tr>
<td>粘贴</td>
<td><code>Ctrl+U</code></td>
</tr>
<tr>
<td>查找</td>
<td><code>Ctrl+W</code> (WhereIs)</td>
</tr>
<tr>
<td>继续查找</td>
<td><code>Alt+W</code></td>
</tr>
<tr>
<td>上一页</td>
<td><code>Ctrl+Y</code></td>
</tr>
<tr>
<td>下一页</td>
<td><code>Ctrl+V</code></td>
</tr>
<tr>
<td>保存</td>
<td><code>Ctrl+O</code></td>
</tr>
<tr>
<td>退出</td>
<td><code>Ctrl+X</code></td>
</tr>
</tbody>
</table>
<h2 id="nano-之外">Nano 之外</h2>
<ul>
<li>
<p>众所周知 <code>man</code> 命令是 manual 的意思,可用来查阅的任何命令的手册,如果我们想要将某命令的内容导出到文本文件中,我们可以使用重定向实现:
<code>$ man command > command.txt</code>
如需导出 <code>ls</code> 命令的手册到 <code>/root/lsman.txt</code> 文件中,命令如下:
<code>$ man ls > /root/lsman.txt</code></p>
</li>
<li>
<p>该文件在 Windows 用编辑器打开会有乱码,我们需要在输出文件前用 <code>col</code> 对控制字符进行过滤:
<code>$ man nano | col -b > /root/nano.txt</code>
使用此参数保存的man手册在各种操作系统或文本查看程序下都可以正常查看</p>
</li>
</ul>
《龙头凤尾》读书笔记
https://acuario.xyz/others/once-upon-a-time-in-HK-clip/
2023-09-27T18:25:39+00:00
2017-03-15T23:50:10+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>人死了,当然一切都完了。尘归尘,土归土,下世投胎要投好。这是我外婆挂在嘴边的话。但她也说过“人死如灯灭”,年轻的我喜欢对她挑衅,问:“如果人死如灯灭,什么都冇了,还投什么胎呀?” 我外婆一边抽烟,一边淡然地自圆其说:“有谁知道呢?可能如灯灭,也可能会投胎,活着的人不知道,死了的人不会回来告诉你。所以啰,最聪明的做法是什么都说一些,什么都信一些,最后不管谁对谁错,两边都有你的份,包无蚀底。” 我一直记得这段话,并深受影响。长大后,我确曾尝试什么都做做,什么都试试,什么都信一些也不信一些,否则不感踏实,没有安全感。可是再长大后,亦即当有了若干年纪,到了中年,始明白,不,不是的,做人必须好好选择,你选了做什么和信什么,就该全心全意去做、全心全意去信,生命太短暂了,把数十年放在做某种人和信某些事之上还嫌不够,若再分心,结果必难成事。 然而又再比长大更长大了些以后,亦即开始老去,终究觉得我外婆说得有道理。但跟谁对谁错无关。而是,谁对谁错又有什么关系呢?你说了,你信了,你体验过了,那才是你的,都是你的,里面都有你的份,等于替生命灌注了不同的可能性,聊胜于无地补救了生命的单一和枯燥。可惜我没法跟我外婆说明这看法,除非人死确实不如灯灭,我还有机会在某个空间、用某种形式跟她重逢。</p>……
<p>人死了,当然一切都完了。尘归尘,土归土,下世投胎要投好。这是我外婆挂在嘴边的话。但她也说过“人死如灯灭”,年轻的我喜欢对她挑衅,问:“如果人死如灯灭,什么都冇了,还投什么胎呀?” 我外婆一边抽烟,一边淡然地自圆其说:“有谁知道呢?可能如灯灭,也可能会投胎,活着的人不知道,死了的人不会回来告诉你。所以啰,最聪明的做法是什么都说一些,什么都信一些,最后不管谁对谁错,两边都有你的份,包无蚀底。” 我一直记得这段话,并深受影响。长大后,我确曾尝试什么都做做,什么都试试,什么都信一些也不信一些,否则不感踏实,没有安全感。可是再长大后,亦即当有了若干年纪,到了中年,始明白,不,不是的,做人必须好好选择,你选了做什么和信什么,就该全心全意去做、全心全意去信,生命太短暂了,把数十年放在做某种人和信某些事之上还嫌不够,若再分心,结果必难成事。 然而又再比长大更长大了些以后,亦即开始老去,终究觉得我外婆说得有道理。但跟谁对谁错无关。而是,谁对谁错又有什么关系呢?你说了,你信了,你体验过了,那才是你的,都是你的,里面都有你的份,等于替生命灌注了不同的可能性,聊胜于无地补救了生命的单一和枯燥。可惜我没法跟我外婆说明这看法,除非人死确实不如灯灭,我还有机会在某个空间、用某种形式跟她重逢。</p>
<hr>
<p>晚上十点多,两人起床穿衣,摸黑走路到谭臣道附近一幢唐楼,为避耳目,他走在路的右边,张迪臣在左边,长长的电车轨道在中间替他们切出了楚河汉界,陆南才觉得两人距离很远很远,乃更有文身的意志,渴望拥有一个永不失去的信物。</p>
<hr>
<p>天下洪门本一脉,孙兴社虽是新堂口,职务分工亦跟其他堂相同,简单明了,有所谓六级八职,坐馆龙头之下是“二路元帅”,再之下是“双花红棍”,左有“白纸扇”,右有“草鞋”,打架的谈判的跑路的,各有所专。在这之下是“四九仔”,还有负责管账的“先生”和仍未正式登堂的“蓝灯笼”,都是自己人。 洪门亦称“三合会”,香港早在一八四五年一月已通过特别法例,任何人只要“自称三合会会员”,即会被抓到法庭起诉。“三合”也者,有道是广东省内东、西、北方合源之意,但另有指福建省云霄县高溪庙始是三合正宗,漳江、南江和渚水于此汇流,万云龙禅在明末崇祯年间聚义抗清,高溪庙是根据地,庙前有对联:“地镇高岗,一派溪山千古秀;门朝大海,三河合水万年流。” 至于洪门之说,同样有分歧,有道是汉人失去中土,“汉”字变“洪”字,以此立名,暗含恢复大汉山河的雄心壮志。也有说朱元璋年号为洪武,起义者一心向明,尊崇旧朝。更有谓陈近南有大将苏洪光,威名震慑清兵,所至之处,天际常现红霞,洪乃“红”的转音,感念祥瑞天佑:</p>
<hr>
<p>陆北才没法确定自己有发问的资格。这一刻,他从胜利者忽然变回失败者,跟以往一样,站在被离弃被背叛的那方,晚上风大,怒风在咆哮。陆北才听见自己心里的风声。也忆起那天夜里,站在张迪臣家门外所曾听见的蝉鸣。</p>
<hr>
<p>陆北才信命,但命运过于复杂玄秘,不可能有人能够准确预测,俗语谓“是福不是祸,是祸躲不过”,唯一能做的几乎是听天由命,许多时候明明是命中注定,你不知道,误以为是巧合,另一些时候却明明是巧合,你不知道,误以为是命运,那就不如遇见什么便是什么,自己判断对应,管它是命不是命。</p>
<hr>
<p>陆北才仍然刻意避开水手馆,免得遇见亨利哥。他有时候到大佛口候客,最近又常到太原街,那边也有许多日本商店,居芝屋料理,明治理发厅,中本洋服店,丸田金店,一郎茶馆,看名字即知道是由日本人经营,就算不看店名,远远望见装潢已可猜到是日本老板,门面都比华店雅致,明亮,进出的客人也都打扮干净简洁,走路时脚步从容,尤其女人,脚步是小而轻,低头,目光朝地,小心翼翼,不想冒犯任何人。可是在这样的时局里,怎可能不冒犯?存在便是冒犯,每个人是单独的每个人,却又都背负着世界的混乱,以及混乱里的怨怼,人被时代辗碎,再搓揉成团块,像厨房桌上的面粉,无论是否看得见,上面都有手纹的污印。</p>
<hr>
<p>来来去去,出出入入,何去何从不管怎么选择都总有理由,只不过有时候是自己不知道,或知道了却不肯承认。而承认了呢,又不见得能被别人接受。甚至有许多选择是否真的由得自己,恐怕也难说,生命仿佛有自己的轨迹,生命的自己比自己的自己更大,更不可掌握。</p>
<hr>
<p>有些事有些人,同在世上却互不懂得。他们那类人,我们这类人,是互不靠近的船舶,却在同一个江湖。</p>
<hr>
<p>陆北才也不再于课后和姐妹们看街景、谈心事了,她没有叫他留下,他亦没有特别去找理由留下,仿佛把心事累积起来,留着,蓄着,顶着,直到某天,时间对了,场合对了,始让洪水漫堤。秘密有时候是道脆弱的墙,明明踹一脚即可踢倒,却偏偏谁都不肯先有动作,墙便永远矗立。</p>
<hr>
<p>“没关系了,其实秘密没你想象的咁重要。知道了就知道了,只不过,守住秘密,本身就很刺激。”</p>
<hr>
<p>到先施后,她们进店,陆北才在路边守候,无聊地留意衣冠楚楚的客人进进出出,黄铜色的旋转门逆时针地被推得团团转,这方向入了一个男人,那方向出来一个女人,蓝衣进,红衣出,似舞台上的魔术帽子,丝巾进,白鸽出。一阵沮丧忽然涌上陆北才心头。世上如果真有一道这样的魔术门,日夜朝晚,随时随地,说变身就变身,该有多好。一辈子只能做一种人,或只被容许做一种人,不管是好人坏人,或男人女人,恐怕都是可怕的损失,任你日子过得如何丰富多姿,总有一些被错过的快乐,永远捉摸不到,只能依靠想象,而愈是想象,遗憾愈见强烈。陆北才没法确定是否应该应该伸手触碰,宁可匆匆碰一下,不喜了,才把手撤回。</p>
<hr>
<p>喝着茶, 抽着烟,喘着气,陆北才沉默着。木店里摆满桌椅柜,以及高高矮矮的关公雕像,有些着了色,有些是原样,木色深浅有异,但姿势一模一样,右手握持青龙偃月刀,左手微扬捋须怒目圆睁,额前刻着月亮,伫立四周包围着陆北才,明明早已在那里,却似这时候始从四面八方蹦跳出来,有话对他说。店内非常宁静,却仿佛飘浮着无数叱喝,洪亮的声音,像在责备,像在斥骂,像在嘲笑,像在教训,像粤剧舞台台上有人在唱大戏,他听不清楚,只知道有许多双男人的眼睛在盯着他。头渐渐痛,一颗心跳得厉害。半晌,声音戛然而止,店里回复外死寂,关公们仍在看他 。</p>
<hr>
<p>恍惚良久,终于睡去,天色转亮之际,陆北才睁眼发现身旁的阿娟仍未醒来,便独自起床走到房外抽烟,抽了几口,随手捡起地上的木头和刨刀,蹲下来,一刀刀地削、割、切。手里的刀动得愈快,世界愈是沉静。锋利的刨刀在木头表面上下磨动,每磨一下,木头即薄一分,一片片木屑被刮起,仿佛时间被刮起,记忆被刮起,一下比一下刨得起劲,把昨夜刮走,把十三岁那年刮走,把往昔的一切刮走,虽然他清楚明白,再如何刨刮,散落地上的碎片依然是木,形体变了,木仍然是木。</p>
<hr>
<p>生命就是这样哕,踏出第—步以前,永远唔知道第二步在哪里,踏完第二步,又有了意外的第三步,每—步其实都在迷路,最紧要系自己觉得开唔开心。</p>
<hr>
<p>以上摘自:
<img src="https://img1.doubanio.com/lpic/s29126758.jpg" alt="《龙头凤尾》"><br>
<a href="https://book.douban.com/subject/26870405/">《龙头凤尾》</a><br>
作者:马家辉<br>
出版社:四川文艺出版社</p>
《你一生的故事》读书笔记
https://acuario.xyz/others/your-life-clip/
2023-09-27T18:25:39+00:00
2017-01-29T21:29:30+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>思维就是在心里,用内在语言说话。</p>
<hr>
<p>人类凭借直观手段发现的物理特性都是某一对象在某一给定时刻所表现出来的属性,诸如运动、速度等概念都是这样。按先后顺序、以因果关系阐述这些事件最方便:一个事件引发另一个事件,一个原因导致一个结果,由此引发连锁反应,事物于是由过去的状态发展到未来的状态。</p>……
<p>思维就是在心里,用内在语言说话。</p>
<hr>
<p>人类凭借直观手段发现的物理特性都是某一对象在某一给定时刻所表现出来的属性,诸如运动、速度等概念都是这样。按先后顺序、以因果关系阐述这些事件最方便:一个事件引发另一个事件,一个原因导致一个结果,由此引发连锁反应,事物于是由过去的状态发展到未来的状态。</p>
<hr>
<p>再来考虑光的折射,光以一个角度触及水,然后改变其路径。可以从因果关系的角度解释:因为空气与水的折射率不同,所以光改变了路径。
这是人类看待世界的方法。如果换一个角度看这个问题:光之所以改变路径,是为了最大限度减少它抵达目的地所耗费的时间。这便是七肢桶看待世界的方法,两种全然不同的解释。
可以将物理意义上的宇宙视为一种语言,其语法极度含混。每一个现象都是一种表述,可以从两种截然不同的角度加以阐释,一种是因果角度,一种是目的角度。两种解释角度都是成立的。无论上下文如何,都不会因此失效。
当人类和七肢桶的远祖闪现出第一星自我意识的火花时,他们眼前是同一个物理世界,但他们对世界的感知理解却走上了不同的道路,最后导致了全然不同的世界观。人类发展出前后连贯的意识模式,而七肢桶却发展出同步并举式的意识模式。我们依照先后顺序来感知事件,将各个事件之间的关系理解为因与果。它们则同时感知所有事件,并按所有事件均有目的的方式来理解它们,有最小目的,也有最大目的。</p>
<hr>
<p>你安静下来时好像会发出一种光。如果有人要替这时的你画一幅像,我会坚决要求他画上这轮光晕。可要是不高兴起来,你简直成了个小喇叭,全部身体构造好像都是有意用来发出噪声。你这种时候的画像就是一个警报喇叭,熊熊烈火中的警报喇叭。</p>
<hr>
<p>自由并不是一种虚幻的假象,在先后顺序模式的意识中,它的的确确是真实的存在。在同步并举式的意识中,自由这种观念却没有多大意义,但同时也不存在“被迫”。两种意识不一样,仅此而已。这就好像在哈哈镜前,看不见照镜子的人,只能看到镜中形象。镜中出现的也许是个绝代佳人,也许是个鼻子上长着大瘤子的小丑,下巴长到胸口。两种形象都是合理的阐释,没有对错可言。但是,镜子中一次只有一个形象,你无法同时看到两个。
与此相类,预知未来又与自由意志产生了矛盾。正因为能够自由选择,所以我不可能预知未来。反过来说,如果我已经知道了未来,我便不可能反抗这个既定的命运,也不可能把我知道的未来告诉其他人——这也是一种形式的反抗。预知未来的人不会奢谈未来,读过岁月之书的人不会承认自己读过它。</p>
<hr>
<p>外交官讲的是人类的道德信仰,极力宣扬人类的利他主义,希望以此为今后的谈判作好铺垫。这场对话的结果七肢桶们知道得一清二楚,但还是积极参与,非常热心。
如果我试图对某个不曾预知这一切的人谈起这些事,他一定会问,要是七肢桶事先早已知道它们会说什么,会听到什么,为什么还要白费唇舌浪费语言?这是一个合乎情理的问题。但问题是,语言不仅仅是一种交流工具,也是一种行动。按照语言—行为理论,诸如“你被逮捕了”、“我将这艘船命名为……”、“我保证”这些语词,其本身就是行为,仅当发出这些语词之后行为才算完成——话一出口,行为即成。对于这些行为而言,预先知道会说出什么话并没有什么关系。婚礼上人人都知道会有一句“我现在宣布你们结为夫妻”,这无关紧要。重要的是主婚人说出这一句话。没有这句话,单有其他仪式是不行的。对于述行语词而言,说话就是行动。
对于七肢桶来说,所有说出口的话都是行为性的。它们所说的话不是用来交流思想,而是用来完成行为。无论什么对话,七肢桶全都事先知道双方会说些什么,这是事实。但为了让它们所知的对话变为真正的事实,对话仍然必须进行。</p>
<hr>
<p>从一开始我就知道结局,我选定了自己要走的路,也就是未来的必经之路。我循路而前,满怀喜悦,也许是满怀痛苦。我的未来,它究竟是最小化,还是最大化?</p>
<hr>
<p>以上摘自:
<img src="https://img5.doubanio.com/lpic/s29091196.jpg" alt="《你一生的故事》"><br>
<a href="https://book.douban.com/subject/26868098/">《你一生的故事》</a><br>
作者:[美] 特德 · 姜(Ted Chiang) <br>
译者: 李克勤 / 王荣生 / 姚向辉 <br>
出版社:译林出版社</p>
部署Hexo到VPS
https://acuario.xyz/posts/how-to-deploy-hexo-to-vps/
2023-09-27T18:25:39+00:00
2016-12-11T23:55:21+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="前言">前言</h2>
<p>最早接触 Hexo 的时候,是通过 Github Pages 进行搭建的,后来遂琢磨着如何才能将博客部署到属于自己 VPS 上去。早前曾尝试过一次,磕磕绊绊,最终卡在了 VPS 部署 Git Hook 的步骤上。
经过一段时间的积累,对 Linux 和相关命令行操作有了粗浅的认识,最近再次尝试 VPS 部署 Hexo 博客,操作起来流畅了很多,也很快搭建成功。打算把这个过程记录下来。
下文是基于 Ubuntu 进行搭建的,CentOS 搭建过程基本一致,只需将安装程序的 <code>apt-get</code> 命令换成 <code>yum</code> 命令即可。文中 <code>$</code> 后均为执行的命令,<code>#</code> 后均为注释,<code><IP地址></code> 均为 VPS 的 IP 地址</p>……
<h2 id="前言">前言</h2>
<p>最早接触 Hexo 的时候,是通过 Github Pages 进行搭建的,后来遂琢磨着如何才能将博客部署到属于自己 VPS 上去。早前曾尝试过一次,磕磕绊绊,最终卡在了 VPS 部署 Git Hook 的步骤上。
经过一段时间的积累,对 Linux 和相关命令行操作有了粗浅的认识,最近再次尝试 VPS 部署 Hexo 博客,操作起来流畅了很多,也很快搭建成功。打算把这个过程记录下来。
下文是基于 Ubuntu 进行搭建的,CentOS 搭建过程基本一致,只需将安装程序的 <code>apt-get</code> 命令换成 <code>yum</code> 命令即可。文中 <code>$</code> 后均为执行的命令,<code>#</code> 后均为注释,<code><IP地址></code> 均为 VPS 的 IP 地址</p>
<h2 id="本地配置">本地配置</h2>
<ol>
<li>
<p>安装 Git</p>
</li>
<li>
<p>安装 Node.js</p>
</li>
<li>
<p>运行 <code>Git Bash</code> 或 <code>CMD</code>:</p>
<pre tabindex="0"><code>$ git config --global user.email "<邮箱>"
$ git config --global user.name "<用户名>"
$ ssh-keygen -t rsa -b 4096 -C "<邮箱>" #默认全部设置最终生成 ssh 密钥 id_rsa.pub
</code></pre></li>
<li>
<p>在 <code>%userprofile%/.ssh/</code> 文件夹下(也就是生成公钥的文件夹)创建 <code>config</code> 文件,输入如下内容:</p>
<pre tabindex="0"><code># Hexo Blog
Host <IP地址>
HostName <IP地址>
User git
Port <SSH端口> #默认为 22
IdentityFile ~/.ssh/id_rsa
</code></pre></li>
</ol>
<p>p.s. Hexo 本地部署相关教程可参考 <a href="https://acuario.xyz/hello-hexo/">Hello Hexo</a>,Git 相关教程可参考 <a href="https://acuario.xyz/how-to-use-git/">Git 简明教程</a></p>
<h2 id="服务端配置">服务端配置</h2>
<h3 id="准备工作">准备工作</h3>
<pre tabindex="0"><code>$ apt-get update #更新 apt-get 源
$ apt-get upgrade -y #升级已有软件
$ apt-get install libpcre3 libpcre3-dev openssl libssl-dev g++ build-essential git -y #安装各种程序和依赖
$ adduser git #密码自己设置,其他可选空
$ chmod 740 /etc/sudoers #变更用户权限设置文件权限
$ vi /etc/sudoers #编辑用户权限设置文件
</code></pre><p>在 <code>/etc/sudoers</code> 文件的用户权限部分添加 <code>git</code> 用户权限:</p>
<pre tabindex="0"><code>### Allow root to run any commands anywhere
root ALL=(ALL) ALL #原有部分
git ALL=(ALL) ALL #添加部分
</code></pre><p>保存并退出编辑,并还原用户权限设置文件权限:</p>
<pre tabindex="0"><code>$ chmod 440 /etc/sudoers
</code></pre><h3 id="nginx">Nginx</h3>
<h4 id="安装">安装</h4>
<pre tabindex="0"><code>$ useradd www -s /sbin/nologin -M #添加用户 www 并禁止 SSH 登录
$ mkdir -p /data/software/ #建立一个放各种软件的目录
$ cd /data/software/ #进入目录
$ wget http://nginx.org/download/nginx-1.10.1.tar.gz #下载 Nginx 软件包
$ tar zxvf nginx-1.10.1.tar.gz #解压
$ cd nginx-1.10.1 #进入目录
$ ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module #配置编译
$ make #编译
$ make install #安装
</code></pre><p>检查 Nginx 是否安装成功:</p>
<pre tabindex="0"><code>$ ll /usr/local/nginx/
total 24
drwxr-xr-x 2 root root 4096 Dec 5 14:48 conf/ #显示结果
drwxr-xr-x 2 root root 4096 Dec 5 14:48 html/ #显示结果
drwxr-xr-x 2 root root 4096 Dec 5 14:48 logs/ #显示结果
drwxr-xr-x 2 root root 4096 Dec 5 14:48 sbin/ #显示结果
</code></pre><p>Nginx 安装到此完成</p>
<h4 id="测试">测试</h4>
<p>仅仅安装是远远不够的,还需要测试一下是否配置正常并启动 Nginx:</p>
<pre tabindex="0"><code>$ /usr/local/nginx/sbin/nginx -t #启动前检查配置文件语法
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok #显示结果
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful #显示结果
$ /usr/local/nginx/sbin/nginx #启动 Nginx
$ lsof -i :80 #查看 nginx 服务对应的端口是否成功启动
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 34317 root 6u IPv4 39180 0t0 TCP *:http (LISTEN) #显示结果
nginx 34318 www 6u IPv4 39180 0t0 TCP *:http (LISTEN) #显示结果
$ netstat -lntup | grep 80 #查看 80 端口的设置
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 34317/nginx #显示结果
</code></pre><p>使用 Web 方式访问本机的外网 IP 时显示如下图:</p>
<p><img src="https://ooo.0o0.ooo/2016/11/15/582ad4c8c3e6d.png" alt="Nginx 初始界面"></p>
<p>如上图正常显示,则表示 Nginx 已成功安装并能正常使用</p>
<h4 id="配置">配置</h4>
<h5 id="配置文件说明">配置文件说明</h5>
<p>Nginx 的主配置文件为 <code>/usr/local/nginx/conf/nginx.conf</code>,其配置<strong>详细含义</strong>如下:</p>
<pre tabindex="0"><code>worker_processes 1; #worker进程的数量
events {
worker_connections 1024; #每个worker进程支持的最大连接数
}
http {
include mime.types; #nginx支持的媒体类型库文件
default_type application/octet-stream; #默认的媒体类型
sendfile on; #开启高效传输模式
keepalive_timeout 65; #连接超时
server { #第一个server区块,
表示一个独立的虚拟主机站点
listen 80; #提供服务的端口,默认80
server_name localhost; #提供服务的域名主机名
location / {
root html; #站点的根目录
index index.html index.htm; #默认的首页文件,多个用空格分开
}
error_page 500 502 503 504 /50x.html; #出现对应的http状态码时,使用50x.html回应客户
location = /50x.html { #location区块,访问50x.html
root html; #指定对应的站点目录
}
}
}
</code></pre><h5 id="规范配置文件">规范配置文件</h5>
<p>一般来说,为了便于各虚拟主机的管理,我们将所有虚拟主机的自配置文件会统一放入 <code>vhost</code> 目录中,并在 Nginx 的主配置文件中添加配置 <code>include vhost/*.conf;</code> 来使 <code>vhost</code> 目录中的虚拟主机的自配置文件加载进来。公共的配置项写在主配置文件中,各虚拟主机的自配置文件则用于差异化,比如规定虚拟主机配置的网站域名或功能取名等等。</p>
<p>先编辑主配置文件 <code>/usr/local/nginx/conf/nginx.conf</code> :</p>
<pre tabindex="0"><code>$ echo "" > /usr/local/nginx/conf/nginx.conf #清空配置文件
$ vi /usr/local/nginx/conf/nginx.conf #编辑主配置文件
</code></pre><p>内容如下:</p>
<pre tabindex="0"><code>worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include vhost/*.conf;
}
</code></pre><p>如下提供一个 host 为 VPS <IP地址> 的虚拟主机的配置文件 <code>/usr/local/nginx/conf/vhost/<IP>.conf</code> 的规范化模板,仅供参考:</p>
<pre tabindex="0"><code>$ mkdir vhost #新建 vhost 目录
$ vi /usr/local/nginx/conf/vhost/<IP地址>.conf #编辑子配置文件
</code></pre><p>内容如下:</p>
<pre tabindex="0"><code>server {
listen 80;
server_name <IP地址>;
root /data/web/<IP地址>/;
index index.html index.htm;
access_log logs/access.log main;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
</code></pre><pre tabindex="0"><code>$ /usr/local/nginx/sbin/nginx -t #检查配置文件语法,报错说明配置文件语法有误
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok #显示结果
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful #显示结果
$ /usr/local/nginx/sbin/nginx -s reload #重启 Nginx,使配置文件生效
$ mkdir /data/web && cd /data/web #新建 web 目录用于 Web 访问
$ mkdir <IP地址> && cd <IP地址> #新建虚拟主机对应的 Web 目录
$ chown git:git -R <IP地址> #授权给 git 该目录权限
</code></pre><h3 id="设置-hexo-对应的-git-仓库">设置 Hexo 对应的 Git 仓库</h3>
<pre tabindex="0"><code>$ su git #切换到 git 用户
$ cd ~ #进入用户根目录
$ mkdir .ssh && cd .ssh #新建并进入 .ssh 目录
$ touch authorized_keys #新建 authorized_keys 文件用于识别 ssh 访问者身份
$ vi authorized_keys #复制粘贴 Windows 的 %userprofile%/.ssh/id_rsa.pub 文件内容
$ cd ~ #进入用户根目录
$ mkdir hexo.git && cd hexo.git #新建并进入 hexo.git 目录
$ git init --bare #初始化仓库
</code></pre><p>在 <strong>Windows</strong> 的 <code>Git Bash</code> 或 <code>CMD</code> 中输入 <code>ssh git@<IP地址></code>, 显示如下则表示设置成功:</p>
<pre tabindex="0"><code>Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '45.76.211.104' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-100-generic x86_64)
* Documentation: https://help.ubuntu.com/
New release '16.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
git@vultr:~$ #这里表示 SSH 成功登录 VPS
</code></pre><pre tabindex="0"><code>$ su git #切换到 git 用户
$ cd /home/git/hexo.git/hooks #进入仓库的钩子目录
$ vi post-receive #编辑钩子设置转发,实现仓库内容同步到 Web 目录
</code></pre><p>编辑内容如下:</p>
<pre tabindex="0"><code>#!/bin/bash
GIT_REPO=/home/git/hexo.git
TMP_GIT_CLONE=/tmp/hexo
PUBLIC_WWW=/data/web/<IP地址>
rm -rf ${TMP_GIT_CLONE}
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf ${PUBLIC_WWW}/*
cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW}
</code></pre><p>授权 <code>post-receive</code> 文件可执行权限:</p>
<pre tabindex="0"><code>$ chmod +x post-receive
</code></pre><h2 id="hexo-发布到-vps">Hexo 发布到 VPS</h2>
<p>修改 hexo 配置文件:</p>
<pre tabindex="0"><code>deploy:
type: git
repo: git@<IP地址>:hexo.git
branch: master
</code></pre><p>发布时进入 Windows 中 hexo 目录,<code>CMD</code> 或 <code>Git Bash</code> 运行发布命令即可:</p>
<pre tabindex="0"><code>$ hexo d
</code></pre>
《纳粹德国的腐败与反腐》读书笔记
https://acuario.xyz/others/corruption-and-anti-corruption-in-nazi-germany-clip/
2023-09-27T18:25:39+00:00
2016-12-04T21:52:49+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h3 id="极权体制下的纳粹腐败和反腐">极权体制下的纳粹腐败和反腐</h3>
<p>英国历史学家理查德·格伦伯格在《十二年帝国:纳粹德国的社会史,1933—1945》一书中写道:“腐败实际上是第三帝国的组织原则。但是大多数德国公民们却不仅忽视了这个事实,而且还确实把新政权的人物当作是在严格地奉行道德廉洁。”纳粹是以严厉抨击和反对魏玛共和国腐败来获得道德号召力的,它“把民主即腐败的信念植入了德国人的集体意识之中”,但是,与纳粹自己的腐败相比,“魏玛时期的那些丑闻不过是政体的小小污点而已”。[1]</p>
<p>[1]Richard Grunberger, The 12-Year Reich:A Social History of Nazi Germany 1933-1945.NewYork:Holt, Rinehart and Winston,1971,p.90.</p>……
<h3 id="极权体制下的纳粹腐败和反腐">极权体制下的纳粹腐败和反腐</h3>
<p>英国历史学家理查德·格伦伯格在《十二年帝国:纳粹德国的社会史,1933—1945》一书中写道:“腐败实际上是第三帝国的组织原则。但是大多数德国公民们却不仅忽视了这个事实,而且还确实把新政权的人物当作是在严格地奉行道德廉洁。”纳粹是以严厉抨击和反对魏玛共和国腐败来获得道德号召力的,它“把民主即腐败的信念植入了德国人的集体意识之中”,但是,与纳粹自己的腐败相比,“魏玛时期的那些丑闻不过是政体的小小污点而已”。[1]</p>
<p>[1]Richard Grunberger, The 12-Year Reich:A Social History of Nazi Germany 1933-1945.NewYork:Holt, Rinehart and Winston,1971,p.90.</p>
<hr>
<h3 id="1933年后对老战士的补偿对党员的庇护和赞助">1933年后对“老战士”的“补偿”;对党员的庇护和赞助</h3>
<p>第三帝国,“补偿”、提携同党与有组织的任人唯亲绝非纳粹统治初期的过渡现象,也绝不是仅限于所谓的“老帝国”境内。在1938年德奥合并之后,这些现象在奥地利同样愈演愈烈。按照“奥地利回归德意志帝国事务特别专员”约瑟夫·比克尔的说法,“奥斯特马克”[18]的党员有着特别强烈的“补偿情结”。这一方面表现在暴力横行的无政府主义行动、劫掠、“疯狂”征用和侵占——这些现象在1938年初是很典型的。</p>
<p>[18]即奥地利。从1918年3月德奥合并至1939年,其仍然保留“奥地利”的名称,随后改称“奥斯特马克”至1942年,最后改称“阿尔卑斯与多瑙帝国行省”。德文中“奥地利”有“东方帝国”的意思,“奥斯特马克”的字面意思是“东方边疆区”。</p>
<hr>
<p>很多企业被纳粹党人占据和劫掠,犹太人和反对派的巨额财产遭到“疯狂”侵占。1938年初夏,经济与劳工部建立了“财产流通办公室”,纳粹党也组建了各式各样的职业介绍和补偿机关,把毫无法纪的个人的中饱私囊引导为有组织的庇护提携,这与“老帝国”的种种现象如出一辙:“国社党的有功之臣”得到安置,纳粹党员得到条件有利的贷款,犹太人的企业被分配给党员,再加上“雅利安化贷款”,以及所有政府许可企业(如烟草商店、彩票销售点、电影院等)系统性的对党员的优待。另外,“老战士”们还能得到金钱奖励,帝国财政部为此提供了2000万帝国马克。总的来讲,奥地利的“补偿”显露出的真面目是“微妙的报复行动”;对党员的庇护和财产再分配比在“老帝国更加彻底和严格”,尽管奥地利纳粹党人对此的解释,即对所谓“在共和国期间为了党的事业而遭受的损失”进行补偿,和在“老帝国”几乎是一模一样的。</p>
<hr>
<p>党的活跃分子们并不因自己得到庇护和赞助而感到羞耻,反而大声疾呼为自己索取“补偿”。甚至于有纳粹党干部因为没有兑现向下属做出的安排工作和提拔的诺言,而被告上纳粹党的党内法庭。1939年8月,汉堡救济部门的一名职员在纳粹党最高法庭如此控告国务秘书格奥尔格·阿伦斯:“因此,我要求,1936年8月向年资较老的党员做出的改善待遇的诺言,也应当向我本人兑现;并且,自1936年秋季以来,我因为没有得到提升而损失的薪酬,也应当补偿给我。”虽然群众对“老战士”得到的优待显然十分不满,但“老战士”们往往对自己的物质特权贪得无厌。国家警察部门报告称,有些“老战士”提出,对岗位和职务的分配应当仅与入党时间挂钩。这些人普遍相信,“老战士对任何部门的工作都是称职的,尤其是,公务机关的领导岗位并不需要专业知识”。这种完全无视个人才干的欲壑难填的心态,即便是在第三帝国的环境下也无法得到满足。虽然纳粹党极力促进党员的利益,但并非所有党员都对自己得到的待遇感到满意。这并不是因为党没有努力去照顾他们,而是因为他们的期望值和要求实在是太高了。而这样的期望值和要求也恰恰是纳粹党自身在其追随者中唤醒和促进的。</p>
<hr>
<p>社会学家特奥多尔·盖格尔早在1932年就指出,在纳粹党人的“理想主义”宣传的光辉外表背后,藏匿着一种没有理想的理想主义,并没有把物质上的贪婪掩饰好。纳粹党人的基本态度是“绝非理想主义的”,而是“极端的经济和物质主义的”:“他们没有克服经济的、物质主义的心态,而是遮蔽着自己的物质主义。”</p>
<hr>
<h3 id="集中营系统与腐败">集中营系统与腐败</h3>
<p>社会民主党流亡理事会的报告指出,纳粹组织内某些犯有前科的人在一个单位犯下贪腐罪行,然后为了躲避侦查就逃之夭夭,随后又混入另一个单位,再次贪赃枉法。当时民间有句流传很广的话,描述的就是这种怪现状:“没有两次贪污或诈骗前科的人,当不了财务总管。”直到1937年之后,贪腐案件的数量才慢慢减少。</p>
<hr>
<p>接受德意志劳工阵线贿赂的还有党卫军少将克里斯蒂安·韦伯,他担任慕尼黑县议会主席、纳粹党议员和“国家社会主义运动之都”的“经济委员”。韦伯被人称为“慕尼黑的福斯塔夫23”,算是最腐化的纳粹党人之一。他的“克里斯蒂安·韦伯盛宴”穷奢极侈,光是慕尼黑市政府就为此支付了1000万帝国马克。韦伯让德意志劳工阵线临时主管卡尔掏钱,给他的宅邸建造了一个“狩猎纪念品陈列室”和一个“男主人书房”,还给慕尼黑—里姆的跑马比赛捐献了一座银奖杯。尽管韦伯收入颇丰——作为县议会主席,他能从慕尼黑市政府拿到7.2万帝国马克;经济委员的薪水是7万帝国马克;从希特勒那里拿到5万帝国马克的赠礼;从慕尼黑市政府还能领取25300帝国马克的“荣誉奖金”——但他居然让卡尔来支付自己宅邸“修理电铃导线”的区区1.5帝国马克!韦伯的所作所为很有代表性,富丽堂皇的外表和中饱私囊的贪欲竟与极度的吝啬如影随形。他对德意志劳工阵线临时主管作了这样的解释:“今天的国家,是我参与建设起来的。那么国家就相当于我自己的公司,因此大可以坦然地接受礼物。”</p>
<hr>
<p>德意志劳工阵线的出纳员哪怕是贪污了一点点钱也会被移交法庭,而政府高官们却在希特勒和莱伊的许可下疯狂敛财,而这财富的最终来源还是纳粹各组织内缴纳会员费的广大会员。因此,纳粹组织内部的腐败在道德上有着双重标准,这再一次清楚地证明,希特勒身边环境中的关系网是多么腐化堕落和纠缠不清。</p>
<hr>
<p>纳粹精英阶层的生活方式还包括如痴似狂的艺术品收藏活动。按照美国历史学家乔纳森·彼得罗普洛斯的说法,这不是因为他们真的热爱艺术,而是由于“个人和集体的自恋”,因为陈设在显眼位置的“古代大师”名画能够彰显其所有者的富裕和权势。这方面就能看出希特勒在纳粹统治集团至高无上的地位:几乎所有纳粹领导人都唯命是从地效仿他那种重古薄今的艺术趣味;在每年“大德意志艺术展”的“采购闲逛”上,元首总是享有优先购买权;对掠夺来的艺术品的支配也明确地属于元首的专有特权。希特勒光是“古代大师”名画就拥有五千多幅。筹备中的位于林茨的“元首博物馆”一旦落成,能够展出的艺术品数量将是巴黎卢浮宫的四倍。</p>
<hr>
<p>一方面是腐败的侵吞手段,一方面是大多数艺术藏品暧昧不清的地位。它们既装点着纳粹领导人的官邸,也装饰着他们的私宅。用来购买艺术品的资金往往既有国家财政,也有私人资金,或捐款,以及可疑的私人特别基金。用国家财政的钱买来的画作常常被轻易送人,于是就变成了私人所有。这种礼物要显示出主人的权势和高雅的生活方式,但最主要的还是加强纳粹统治集团内部的关系。因此,希特勒不仅从下属那里收受艺术品礼物,也向他人赠送艺术品,以收买人心。
这种附庸风雅行为的一个奇怪方面是,甚至连马丁·鲍曼和罗伯特·莱伊这样的雇用兵一般的大老粗也购买了大量艺术品,因为他们要对希特勒亦步亦趋、上行下效,而且深知艺术品收藏在纳粹权力体制中作为身份象征的重要意义。希特勒似乎想要讽刺下属附庸风雅的行为,于是在罗伯特·莱伊生日时赠送给他一幅汉斯·格吕茨纳的画作,这幅画与德意志劳工阵线全国领袖的本性及其公众形象倒是颇为相符。这幅画的标题是《狂饮的僧侣》[25]。</p>
<p>[25]罗伯特·莱伊是有名的酗酒狂徒。</p>
<hr>
<p>第三帝国的腐败的典型元素在劳改营、战俘营和集中营系统也很普遍,尤其是集中营,几乎是整个腐败体制的缩影。集中营发生严重腐败的最重要的结构原因早在纳粹统治初年就已经出现了,一个个集中营被作为不受外界监管的隔绝空间建立起来:集中营既不受普通行政机关管辖,也不听从传统政府当局的领导,因此集中营的财务完全不受国家财政监管体制的影响,况且集中营完全不受司法部门的控制,与公众之间也是隔绝的。</p>
<hr>
<p>早期集中营的看守人员往往是无业的纳粹党活跃分子和街头打手,他们的特点是既残暴野蛮,又贪婪腐化。集中营事务总监特奥多尔·艾克在给党卫军全国领袖海因里希·希姆莱的一封信中写道,达豪集中营的第一批看守人员是“120人的腐败警卫队”,最突出的特点就是“贪污腐化”。犯人进入集中营时带来的贵重物品以及其家属寄来的钱和包裹都会被看守私吞掉。党卫军看守利用犯人来“搜罗”物资,来满足他们的私人需求,还利用集中营的现有设施,比如木工作坊,来为自己打造家具陈设。关于里希腾堡集中营的一份报告指出,“绝大部分看守都肆无忌惮地中饱私囊,不这么做的人是极少数,而且越来越少”。</p>
<hr>
<p>汉斯·洛里茨于1936至1939年担任达豪集中营指挥官,1940至1942年担任萨克森豪森集中营指挥官。他无论是在集中营内,还是在外界,都过着骄奢淫逸的生活。比如,萨克森豪森集中营的防空洞里设有一座“日耳曼式的啤酒酒窖”、两条保龄球道和一套打靶设施,以便让指挥官大人在躲避空袭期间消遣。党卫军内部把这些设施称为“游乐场”。洛里茨命令囚犯在沃尔夫冈湖畔圣格尔根给自己建造了一座豪华别墅。当年的一位犯人就此报告称:“洛里茨享受着自己的地位带来的所有好处。他让人从萨克森豪森集中营向圣格尔根送去了四辆卡车的炼砖和木材。有犯人为他创作油画;犯人给他编织了大约60幅地毯;还给他制作皮制灯罩、洗衣篮、桌子、编织沙发、带白银装饰手柄的镇纸、精美的牙签;另外还有三扇窗户的铸铁栅栏,光是这个就让四名犯人干了两个半月。”</p>
<hr>
<p>在1942年的一次大规模人事变动中,大约三分之一的集中营指挥官被替换,前文所述的三名指挥官洛里茨、皮奥尔科夫斯基和科赫也丢了乌纱帽。腐败虽然是很多指挥官被撤职的原因之一,但不是决定性的原因。更重要的是,集中营的功能发生了变化,转换为利用犯人为战争经济服务。经历过“斗争年代”的老指挥官们不再适应这一新职能,因为他们的领导作风就是残暴、腐化和酗酒。另外,腐败不是将这些人撤职的理由,而是因为,这些指挥官的豪华别墅和黑市买卖过于张扬,有将集中营的秘密暴露给公众的危险。</p>
<hr>
<p>在党卫军全国领袖看来,腐败行为危及了党卫军的道德准则,阻碍了他在党卫军内部将大屠杀和“正直”和谐起来的努力。按照他的逻辑,如果一名大屠杀凶手在杀人时完全是无私地执行自己的义务,而不谋求私利,那么他也可以说自己是个正直的人。但与此同时,希姆莱从来不会让他自己的这种道德观牵着鼻子走,而是同样考虑实效和权力政治方面的因素,因此他对反腐调查的态度显然是摇摆不定的。但雪崩般大爆发的众多腐败案件也清楚地证明,希姆莱扭曲的意识形态的“正直”观念完全脱离了党卫军的实际。</p>
<hr>
<p>卡琳·奥尔特在对党卫军集中营的研究中指出,“正直”的观念建构对一部分集中营指挥官来说,是他们的自我认识的一个核心部分。正是由于将自己与科赫这样的腐化指挥官划清界线,他们才能忠于希姆莱的理想,更加坚决果断和冷酷无情地按照党卫军的世界观基本原则行事。这是毫无疑问的,尽管这种“正直”形象的背后隐藏着一种事后的自我粉饰。在1945年后的调查和审讯过程中,党卫军人员的这种自我涂脂抹粉是一种辩护策略,起到了很大作用。但即便用希姆莱观念中的“正直”的指挥官来取代科赫这样的腐败高官,也仍然无法根除集中营中的腐败,因为腐败的体制原因仍然存在。因此,丝毫不奇怪的是,党卫军法官摩根在1944年6月,也就是腐败的指挥官皮奥尔科夫斯基被撤职两年后,在达豪集中营调查时发现了“数量巨大的来自意大利的劫掠物资(布料、肥皂、食品和享乐用品)”,这些物资“被大规模地偷窃和倒卖”。尤其是集中营管理人员贪污食品的行为导致犯人出现了灾难性的营养不良,这在很大程度上导致了使用奴隶劳工的企业利润极差。
在战争的后半期,东欧的死亡营中的腐败猖獗到了让此前“老帝国”的所有集中营都黯然失色的地步。比如,在奥斯维辛,犹太犯人刚刚抵达就遭到腐败的警卫和党卫军军官的无情洗劫,珠宝、手表、黄金、货币和外汇都被大规模地侵吞。或者,例如在索比布尔集中营,犹太人甚至在死后还要被警卫们加以“利用”,谋取私利。这些警卫私自建立了一个秘密的金匠铺,将犹太人的金牙熔化并打成金条,塞入集中营管理人员的腰包。希姆莱的那种扭曲变态的“正直”观没有改变集中营腐败的体制原因,这些原因不仅在集中营中,在其他的劳改营、战俘营等地方也很有影响。</p>
<hr>
<h3 id="大屠杀与腐败">大屠杀与腐败</h3>
<p>这个国家破坏了自己的一块基石:它腐蚀了自己的公职人员。犹太人遭到的劫掠,终有一天会以雅典悲剧的标准得到复仇。掠夺犹太人的国家让自己的公职人员也犯下了罪孽,享受劫掠来的财富,这样的国家必将灭亡,因为它的公职人员已经道德沦丧,毫无礼义廉耻。……我的一个熟人卷入了一起关于外汇的刑事案件。让人意外的是,他很快被释放了。“你花了多少钱去打通关节?”这句老百姓的口头禅标志着曾经很干净的德国现在已经脏成了什么样。“从5马克到5万马克不等。从狱警到最高机关,全都收了钱。”</p>
<p>汉斯·赖希曼的描述表明,在纳粹政权隐秘地剥夺犹太人权力、消灭其经济基础、强迫其移民、最终是驱逐31和谋杀的所有过程中,始终都伴随着纳粹统治下典型的五花八门的腐败行为。其实官方发布了连篇累牍的规定和命令,要求“依法”处理犹太人问题,严禁个人和机构借此机会中饱私囊。这就使得迫害犹太人过程中的腐败更值得注意。</p>
<hr>
<p>“国家社会主义人民福利行动”柏林分部的工作人员用一种特别奸诈的手段来填充自己的腰包:他们在明知某些人是犹太人的情况下,仍然将他们吸纳进来,然后把他们传唤过来,指控他们“潜入国家社会主义人民福利行动”,以勒索钱财。</p>
<hr>
<p>对总财务官来说,最重要的是,党组织通过“雅利安化”发财是可以的,但必须向他报告和申请批准。只有那些在施瓦茨不知情的情况下做出的中饱私囊行为才会让他恼火,因为这种行为削弱了他对党内财政的中央管辖权。在“雅利安化”过程中,在纳粹党的各种组织机构和地区机关大量建立起来的特别基金和小金库具有财政上的独立性,因此同样也削弱了施瓦茨的中央财政分配权力。总财务官向副元首的幕僚长指出了这样一种危险:“各省部书记利用这种形势,建立了自己的小金库和基金,在未经我许可的情况下自行支配。”看来,施瓦茨正式地禁止党组织从“雅利安化”得利,绝不是为了在“雅利安化”框架内保护国家的利益,而完全是为了巩固他本人在党内的权力地位。</p>
<hr>
<p>另外,在“雅利安化”的环境中,还有很多犯罪分子利用犹太人的绝境大发横财。犯罪分子向犹太商店索取“保护费”;野鸡律师装作搭救遇险的犹太人,拿了律师费预付金后就消失得无影无踪;还有人伪称自己和纳粹党高级领导人有关系,向犹太人许下天花乱坠的诺言,骗得钱财,这些诺言完全是空中楼阁。在“雅利安化”末期,德国境内急于出境的犹太人数量剧增,很多外国领事馆,尤其是南美洲和中美洲国家的领事馆,在发放签证时收取高价。要搞到一本前往阿根廷的入境签证,每人要缴纳5000帝国马克的贿金;去海地的签证就只需要1000帝国马克。这种贿赂救了很多犹太人的性命,被犹太移民称为“行善的腐败”,被认为不完全是坏事,尽管这些贿金首先被官员们私吞,并且对移民来说也是一种经济上的掠夺。</p>
<hr>
<p>腐败在“雅利安化”框架内发挥的作用有两个方面。首先,腐败,尤其是“官方”的、以赞助和提携为表现形式的腐败,将获益者直接地与纳粹统治系统捆绑在了一起,即便这些赞助往往并不是为了保证获益者未来的忠诚,而是被理解为对党员在过去做出的物质上的“牺牲”的“补偿”。所谓的在“斗争年代”做出的“牺牲”与1933年后的“补偿”之间的联系构成了“救赎式反犹主义”的一个重要的社会心理元素。绍尔·弗里德伦德尔认为,“救赎式反犹主义”是一种具有特别的德国特色和纳粹特色的反犹主义。
其次,利用犹太人财产中饱私囊的行为使得反犹政策更加极端化,因为对犹太人的掠夺造就了一群数量不断增长的既得利益者,他们绝不愿意将吃下的东西再吐出来,因此绝不愿意看到犹太人业主回来索回自己的财产。这些既得利益者跨越了道德上的卢比孔河,只能在反犹道路上继续走下去,并且更加极端化,因为他们假如要往回走,就必须承认自己的罪孽,并将侵吞来的财产返还原主人。</p>
<hr>
<p>1943年在慕尼黑活动的“雅利安化办公室”也从富裕犹太人那里敲诈数额巨大的“捐款”,并保证不会将他们驱逐到东欧。事实上,几乎所有人在捐款之后当即就被驱逐了。就像盖世太保的“登门拜访”一样,腐败也让驱逐和灭绝的措施更为极端化,犯罪者利用这些措施,消灭知情者。</p>
<hr>
<p>在大城市,被出售的犹太人财产都是“没名没姓”的,买家更不会有道德顾虑。
纳粹统治者老谋深算地用这种手段来腐蚀群众的道德,他们认为,德国人民越是彻底地断绝了自己道德上的退路,就越能强烈地认同和支持纳粹统治,也就会更加“狂热”地为“最终胜利”而战。宣传部长戈培尔就此在日记中写道:“尤其是在犹太人问题上,我们已经走得这么远,绝没有任何退路了。这样也好。已经破釜沉舟的政治运动和民族,战斗起来要比还有退路的人坚决得多。”
但纳粹党的这个算计在战争末期却被证明是落了空的。一位汉堡的犹太商人由于“享受特权的跨种族婚姻”而在纳粹统治中活了下来,他在1945年初在自己的私人文件中写道,一部分德国群众对盟军即将取得的胜利非常恐惧。他写道:“很多占据了犹太人房屋和财物的人,今天非常害怕,担心犹太人会卷土重来,索回自己的财产,然后控告他们的抢劫和盗窃罪行。”
考虑到纳粹灭绝政策实施过程中发生的劫掠、“疯狂的”中饱私囊、未经授权的没收以及不受监管的对犹太人财产的分配和浪费到了多么惊人的规模,就可以得出结论:腐败绝非孤立的边缘现象,而是体制固有的普遍现象,或者说是纳粹统治系统的一个根本性行为。</p>
<hr>
<p>一些历史学家和社会学家将纳粹对犹太人的大屠杀看作精确运转的官僚机器的齿轮组。比如,汉斯—京特·阿德勒的巨著《被管理的人》就持这样的观点。劳尔·希尔贝格认为纳粹官僚具有“不可腐蚀的计划和管理上的细致缜密”。一个非常夸张的例子是,社会学家齐格蒙·鲍曼将纳粹国家的体制阐释为马克斯·韦伯设想的那种官僚体制。而历史真相与上述的这些观点是不相符的。鲍曼对纳粹统治手段,比如帝国保安总局所属机构或占领区行政机关的世界观责任的认识是错误的。纳粹体制的结构和行为与韦伯描述的官僚体制概念的范畴完全无法调和。
当然,如果没有现代国家的官僚机构,对欧洲犹太人的规模如此之大的屠杀是不可能办得到的。但我们绝不可以简单化地将大屠杀视为一场不带个人感情的、官僚的、精确执行的国家罪行。专断残暴、个人和组织的公开谋取私利、个人的极端手段和措施,以及有时达到无政府主义程度的对犹太人的掠夺和谋杀——这些同样是大屠杀的特点。谋求物质利益不是大屠杀的动因,而只是它的一个伴随现象。但对于很多参与者来说,物质利益却是一个不可低估的动机。除了意识形态的狂热和道德败坏的官僚常规外,“低级”的动机(比如贪婪),也对大屠杀起到了推动作用。在这样一个统治系统——重要的国家机构的运作不再受到正常原则的约束和监管,受害者被剥夺人性,受害者的财产则被以意识形态手段诬蔑为赃物——内,腐败找到了理想的温床。</p>
<hr>
<p>纳粹党人试图把杀害犹太人的行为按照意识形态分成两类:要么是谋杀,要么是,按照希姆莱的话说,“在过去和将来都永远不会被书写下来的光辉一页”。但蔓延的腐败让这种区分很成问题。如果某人是在上级的保护和授意下,或者凭借公职权力杀死犹太人,那么就算在此过程中捞点油水,也不用担心受到刑法追究。如果凶手在此过程中表现出了“低级动机”(这是谋杀罪名成立的一个重要因素)——如贪婪、虐待狂、奸诈——虽然官方对此不能接受,但却默许地予以容忍,因为“低级动机”在功能上对大屠杀有用。只有那些追求私利,并且在体制框架之外杀死犹太人的凶手,才会被视为谋杀犯,遭到严惩。</p>
<hr>
<h3 id="放走老虎内特林案和马尔迈斯特案">“……放走老虎”:内特林案和马尔迈斯特案</h3>
<p>“世界上没有任何一个其他政权,能够像国家社会主义政权这样,对所有形式的腐败展开如此彻底和坚决的斗争。”党卫军法官康拉德·摩根于1943年如此浓墨重彩地赞扬了第三帝国的反腐措施。在纳粹政权典型的自吹自擂中,为了将纳粹主义装扮成政治廉洁的化身,他们丝毫不会吝惜夸张的形容词,尽管宣传和真实情况——纳粹政权在体制上缺乏反腐能力——之间有着巨大的鸿沟。</p>
<hr>
<p>1933年5月,纳粹政府对欺诈和贪腐的量刑标准予以提高,“情节严重的”可以判处最高十年监禁。“情节严重”是指“人民的利益受到损害”。这是典型的纳粹法学概念,弹性极大,可以随心所欲地加以解释。</p>
<hr>
<p>第三帝国蔓延的腐败问题的体制基础早在1933年初的“夺权”阶段就已形成。柏林的国家特别专员利珀特的专制手段——利用“保护性监禁”敲诈钱财——就是一个生动的例子。政治分权制度被废除,所有能够实施权力监管、阻止腐败蔓延的分权制衡机制都被排除掉了。议会被解散,或者被改造成唯一功能就是为领导人鼓掌喝彩的拍马机器。于是议会对行政权力起到平衡作用的监管功能也消失了,对财政的监管权、对违法行为的公开讨论、批判性的质询都不复存在,也不可能由议会任命监管和调查委员会。</p>
<hr>
<p>第三帝国的统治者在短短几个月内就摆脱了对自己的行为做解释的所有责任,并通过对新闻界的“一体化”,让公众的批评都噤声了。在1933年之前,新闻界还能让很大一部分公众知晓当时的腐败现象,调动他们的情绪,甚至使得他们做出过激反应(右翼在反对魏玛“体制”的斗争中对此加以了利用)。1933年之后,新闻界的领导者就确保读者只能读到对政府的丰功伟绩歌功颂德的宣传。只有在统治者认为有利的时候,才会允许对贪赃枉法行为做报道。有的时候,这种报道非常晦涩模糊,读者必须要有读懂字里行间言外之意的本事才行。新闻界在报道针对贪腐纳粹党官员的诉讼时,会对被告的政治身份做出非常艺术性的改写。于是,纳粹党的政工干部在报道中就变成了“在某位任职的领导干部”。</p>
<hr>
<p>对于腐败分子来说,除非他们卷入了体制内部的权力斗争,或是在自己的靠山和保护人眼中失去了所有的利用价值,或是侵吞了党及其组织的财产,否则就不必害怕自己的腐败行为受到检举控诉。在贪污党产方面,仅从1934至1941年,纳粹党总财务官施瓦茨就在普通法庭提起了10887项诉讼。当然,如此之高的数字也仍然只是冰山一角,因为只有那些由纳粹党总财务官提出的刑事诉讼才会被提交到普通法庭,而国家检察官被明确禁止独立开展调查,也无权没收纳粹党的账簿和财务凭证。因此,法庭在判决时只能完全依赖纳粹党总财务官及其审计员提供的信息。另外,纳粹党总财务官还有权要求将案件进行秘密审理,可以指定证人和专业鉴定人员,或者将审理进程限制到个别犯罪事实上。纳粹党总财务官的审计员作为证人、专业鉴定人员和观察员参加庭审,对法庭进行监视,确保法庭遵守上述原则。于是,司法部门的调查和审理的空间被限制得很死,只有纳粹党总财务官认为有利的那些党内腐败案件才会受到审理。总财务官会从政治、私人关系或其他因素上考虑,对某些贪腐分子不予处罚,于是这些案情就会被遮掩起来。</p>
<hr>
<p>在有些案件中,腐败的纳粹党人损害的不是纳粹党及其组织机构的利益,警察和司法部门的调查和活动空间就大很多,因为他们不需要屈从于纳粹党总财务官的严格规定。但在这些案件中,他们却常常遇到纳粹高官的顽强抵抗。这些高官认为庇护自己的下属是天经地义的事情,而且他们在“斗争年代”就养成了对警察和司法部门的强烈憎恶。</p>
<hr>
<p>在第三帝国,反腐不仅仅是主管的司法机关的责任。尤其是,政工干部对司法部门施加的影响会将刑事调查和审理转移到政治领域中。甚至是否提起诉讼,就已经是个政治问题,因此要在政治领域内解决。
于是,很多腐败的纳粹党人虽然犯罪事实铁证如山,但还是能够逍遥法外,因为他们能够找到政治靠山。这些靠山会把调查程序撤销,或者为他们争取宽大处理</p>
<hr>
<p>除了对司法部门施加影响之外,有些纳粹党人还有一种办法可以阻挠纳粹党官员受到处罚:他们将案件,尤其是腐败案,移交给纳粹党自己的法庭,在党内部处理案件,把普通法庭排除出去。纳粹党内法庭的前身是1933年以前的调查与调解委员会(Uschla),从党支部领导人以上,由具体负责的高级领导人管辖。这些高级领导人有权将主管法官撤职。根据1934年2月纳粹党中央发布的指令,党内法庭的最高职责是维护党及其成员的声誉,并对意见分歧进行调解。正因为此,党内法庭算不得真正的独立司法机关,而是党内机关,它存在的理由就是为了从政治上利用它。因此,党内法庭的判决是由纳粹党的朋党之交、门阀和小集团结构来决定的,于是被告能够受到什么样的处理,首先取决于他在党的等级结构中的地位,他是否从属于某个特定的统治小集团,以及政治上和私人关系上的机会主义。</p>
<hr>
<p>党内法庭要随时为纳粹党干部服务,但绝不能成为一支能够对党的干部指手画脚,甚至对其有约束力的独立力量。1942年,最高党内法官布赫胆大包天地反对希特勒的一项决定,将省部书记约瑟夫·瓦格纳开除党籍,遭到了希特勒狗血喷头的痛斥,党内法庭的政治势力一下子锐减为零。1942年11月21日,希特勒在命令中指示,党内法庭不应当“根据正式法律的观点,而是应当遵照党的运动的政治需求”进行裁决。
“元首”对持久的反腐斗争并无兴趣。他自己就利用提携和赠礼的体制来巩固自己的权力地位,以及赏赐忠实的追随者。谁要是做出对他本人不忠不孝的事情,或者触犯了纳粹意识形态的基本原则,希特勒是极其严厉、绝不宽贷的;但对于部下的中饱私囊和腐败行为,他一般是会罩着的。第三帝国期间被撤职的所有省部书记和政权高级领导人中没有一个是因为腐败倒台的。“如果我们这里有人因为腐败被判刑,我们不可以说:看哪,这都是什么世道!这都只是个案而已!”希特勒有一次在餐桌上谈话时把腐败问题就这么不屑一顾地打发掉了。
只有在一个方面,希特勒会比较敏感,那就是“党或国家公职人员与私营经济的联系”这个话题。1942年他有一次滔滔不绝地就此话题谈了一整夜。他批评了有些帝国议会议员在私企董事会任职的事情,并要求党的领导干部“不要牵扯到私营经济利益中去”,甚至尽可能不要收受私企的好处。有139名帝国议会(议会本来也没有什么影响力)议员遵照指示,放弃了在私企董事会的职务,但大多数干部都把希特勒的这番命令当作耳旁风。希特勒这么做倒并不是因为反对腐败,而是因为他首先要确保自己个人的地位。他要党的领导干部直接地、彻底地忠诚于他一个人,而不是同时还要兼顾私企的利益。</p>
<hr>
<p>只有在少数案件中,帝国保安总局才动用了党卫军和警察的司法部门来调查审理,因为党卫军和警察内部官官相护,保护自己人不受查处,而且上级也很少会揭发部下的过失。在这个由暴力、中饱私囊和非常规的行事方式焊接而成的密谋小集体内,谁要是告发同事或上级的腐败行为,不仅没有人相信他,他还会被认为是爱发怨言的牢骚鬼,被疏远、被处分调离。一名刑警专员检举同事的腐败和黑市交易行为,却被以“滥用职权、胁迫他人”的罪名关押了六周之久,在此期间他的同事们把全部对自己不利的证据消灭得一干二净。最后这名刑警专员被贬到了一座“劳改营”任职。</p>
<hr>
<p>1942年3月21日,希特勒发布“关于领导干部的生活方式”的命令,要求他们“做出表率”,“一丝不苟地、理所当然地严格削减开支”。谁若是胆敢抗命不遵,“不管是谁,不管他的地位有多高,一定严惩不贷,绝不姑息”。1942年4月26日,希特勒在帝国议会的一次讲话中指出,必须要将“疏忽失职行为从国家机关无情地驱逐出去,不管是谁,也不管他有多大的权力”。根据党卫军保安处的调查,民众对希特勒的这次讲话十分欢迎,认为它是“反对任何形式的腐败和渎职行为的不留情面的斗争动员”。但另一方面,群众同时还希望能够“撤除一些领导人的职务”,“无情地大力查处更多的腐败案件”。
下文将证明,由于纳粹领导人的官官相护,这种反腐声明根本就是雷声大雨点小。没有一个高级领导人因为腐败而落马。但是政府已经把自己逼到了风口浪尖上,如果不做些什么,就无法向群众交待了。从1942年初开始,群众产生了一种期望,要求政府严惩一批贪腐分子,以儆效尤。为了满足群众的要求,政府不得不丢车保帅,采取一些象征性的反腐措施。</p>
<hr>
<p>纳粹党及其组织遮掩腐败行为的做法在过去一直很成功,在“亚诺夫斯基案”中却失败了,这是因为警察和司法部门已经从柏林获得了明确的政治支持。各机关的代表人已经达成一致,要利用此案做个象征性的文章,牺牲掉一个省部干部,反正他也不属于纳粹党的领导层圈子。
这个决定是于1942年6月27日在柏林的一次会议上做出的。参会的除了“国家社会主义人民福利行动最高指挥官”希尔根菲尔特之外,还有帝国保安总局、纳粹党总财务官、纳粹党中央办公室的代表。根据调查,希尔根菲尔特自己在此案中也陷得很深。他起初试图把案子遮掩住,但后来因为急于洗清自己、与罪犯脱离干系,于是装模作样地要求对涉案的“国家社会主义人民福利行动”官员“严惩不贷”。帝国保安总局的代表,党卫军少校尤斯图斯·拜尔指出,有鉴于当前的国内政治形势,“群众的情绪及元首最近一次讲话都要求对此类案件大力查处”。他的这个态度得到了党卫军全国领袖海因里希·希姆莱的全力支持。在这些压力下,纳粹党总财务官的代表也调转到强硬路线上,主张“对罪犯予以无情的严惩”。
于是,基尔特别法庭于1942年8月28日,根据《民族败类处罚规定》第4条,将“国家社会主义人民福利行动”省部领导人亚诺夫斯基、县级领导人赫尔曼·施特格曼、省总部领导人库尔特·埃克霍夫判处死刑,将另外15名“国家社会主义人民福利行动”官员判处两个月至八年不等的监禁。但这个判决能否真正得到执行还是个问题,因为在幕后又发生了激烈的争论。这再一次表明,司法部门不具有独立性,依赖于政治领导层,并受其利用。</p>
<hr>
<p>尽管这个判决并没有公之于众,但根据基尔总检察长向帝国司法部的报告,它“在群众所有圈子里都成了激烈争论的话题”。很多老百姓对判决能否得到执行表示怀疑,并猜测,判决“只是纸面上的”,只不过是场“闹剧”而已,所有被判刑的人“至迟到战争结束”就自由了。有传闻说,亚诺夫斯基的妻子每个月能从“国家社会主义人民福利行动”拿到600帝国马克的抚养金,这让群众更加“情绪激动”了。总检察长称,群众中出现了“集体的精神极度不安”,这对党和司法部门的声誉造成了损害。</p>
<hr>
<p>严酷的量刑尺度和动用《民族败类处罚规定》来打击腐败的党干部的做法在1942年之后虽然向群众显示了政府“无情打击”腐败的决心,但绝非真正成功的反腐行动。从下文的内特林和马尔迈斯特的腐败案可以看出,将个别贪官污吏处死的做法只是证明了群众中流传的那句顺口溜:“打死苍蝇,放走老虎。”尽管一些贪腐分子受到严惩,尽管希特勒命令领导干部要生活节俭,纳粹政权在战争的后半期仍然没有办法迫使党的领导人遵纪守法,对同样的犯罪行为仍然像以前那样,使用双重标准。</p>
<hr>
<p>在1942年6月,帝国皮革管制委员会在一次企业审查中识破了马尔迈斯特的花招,发现有很多人在没有配给证的情况下从他那里购买了定制皮鞋,有时是用实物交易的。马尔迈斯特的主顾的名单简直就是第三帝国的名人录,其中赫然有:希特勒、戈林、帝国新闻总长奥托·迪特里希博士、党卫军上将维尔纳·洛伦茨、省部书记恩斯特·威廉·博勒、国务秘书奥托·迈斯纳博士、国务秘书保罗·克尔纳、国务秘书赫伯特·巴克、党卫军上将威廉·比特里希、希特勒的副官党卫军中将尤利乌斯·绍布、希姆莱的副官党卫军准将鲁道夫·冯·阿尔文斯莱本、帝国部长拉默斯的女儿和女婿,以及帝国组织部长莱伊的儿子。
帝国皮革管制委员会火速决定,对上述人士不再进行任何调查,而是将调查局限于那些不属于国家领导人的顾客们。帝国司法部也立即加入了对此案的遮掩。部级领导约埃尔博士作出指示,“对于部级主任以上”,地方警察当局不得对其进行讯问。最后几乎所有针对顾客的调查都被叫停,只有马尔迈斯特自己因为战争经济犯罪被判了三年徒刑。特别法庭对马尔迈斯特格外开恩,因为此案没有造成公众影响。在审讯过程中,他的大部分主顾的名字都被隐去,案件卷宗上盖着这样的章:“根据帝国刑法第83条,此案属于国家机密。”
此案再次证明,纳粹政权的领导人享有一种特殊地位,哪怕是腐败的事实已经被证实,也不用害怕受到处罚。1942年之后和之前相比的唯一变化是,高级领导人为了安抚群众日渐高涨的不满情绪,愿意牺牲掉中下层的官员,以便转移群众对自己的过失的注意力。纳粹统治系统的结构对于所有的反腐努力来说都是刀枪不入,因为原本有可能起到调查作用的机关几乎总是自己束住自己的手脚,就像马尔迈斯特案中的帝国皮革管制委员会和帝国司法部那样,它们对遮掩腐败案的做法早已烂熟于心,主动放弃了任何形式的批评检查。</p>
<hr>
<p>在第三帝国垂死挣扎的剧痛中,纳粹政权的领导层再次掀起了疯狂的反腐活动,成立了新的机关,如“陆军中央法庭”;海因里希·希姆莱在1944年12月发布了一道关于打击内政部门(即传统的职业官僚领域)腐败的荒诞命令;帝国审计总署署长在1945年初大声呼吁要加强反腐。所有这些“措施国家”的上蹿下跳式的活动不仅来得太晚,而且仍然没有触及纳粹政权内所有滋生腐败的体制。1933年以来的事件证明,如果没有权力监管和分权制衡,没有针砭时弊的公众和新闻自由,如果所有的政府机关都不遵守常规的原则,如果没有独立的监管机构,所有的反腐行动都注定要失败。</p>
<hr>
<h3 id="腐败与民意">腐败与“民意”</h3>
<p>自1933年以来,腐败就一直是群众热衷的谈资。它在政府宣传的官方渠道越是被视为禁忌,在群众中就越是发展成一种私下里的“热门话题”。尽管纳粹党人对这方面的“民意”的尊重很有限,例如只是在战争后半期象征性地查处了一些腐败党员,但监视民情的政府机关却对群众的批评和不满作了细致入微的记录,正如盖世太保和党卫军保安处的形势报告能够详细证明的那样。
“不是干部观察群众,而是群众在观察干部,而且是目光敏锐地观察。”国家警察科隆分局在1935年如此描述群众对腐败这个话题的敏感度。在纳粹统治的最初几年,几乎所有的国家警察分局都记录到了群众“对贪官污吏统治和贪污腐败的怨言”。</p>
<hr>
<p>被政府宣传控制的新闻界对这种事情讳莫如深,但这也压制不了群众的怨声载道。恰恰相反,“被驯服的新闻界的沉默”——这是萨克森省长的讽刺说法——对政府来说不但无效,反而有害,而且更助长了谣言的散布。由于遮掩事实和刻意沉默,政府丧失了所有辟谣的机会,导致关于腐败的谣言四处传播,贪腐的金钱数额也被大大夸大。“政府越是不允许群众去一探腐败泥沼的究竟,群众就越是热衷于这个话题,并试图自己去探究,究竟发生了什么事情。”社会民主党流亡理事会关于德国事务的报道在1936年如此描述新闻封堵和造谣传谣之间的关系。</p>
<hr>
<p>在1938年1月,流传着一封《致弗兰肯零售业人士的公开信》,其中详细描绘了省部书记的奢侈生活,最后一段是:</p>
<p>如果元首阿道夫·希特勒要求我们这么做的话,我们会心甘情愿地将全部(原文为着重体)营业额和最后一个芬尼都捐献出来!但对于一个贪官污吏——甚至最腐败的赤色体制也不会滋生出这样的腐败分子来——对于一个贪图享乐的人,一个四处大吼大叫的游手好闲之徒,我们一分钱也不给。他的别墅、破产的庄园、汽车、“电影明星”和剧院小婊子,他的出国旅游,以及让同伙闭嘴的收买人心的钱,都应当让他自己付账!</p>
<p>这封公开信的语气虽然非常强烈,但对希特勒本人的正面评价却表明,群众对腐败的批评几乎从来不会对整个纳粹统治提出质疑,而是对政权提出有限的批评。“如果元首知道这事就好了!”这样口口相传的话对于群众的基本态度,即在针砭时弊时几乎总是对政府仍然赤胆忠心来说是非常典型的。早在纳粹统治的初期,国家警察机关就在其形势报告中指出,群众不仅对希特勒本人没有任何批评,而且纳粹“金雉鸡”[39]们的丑行越是被揭露出来,元首的形象就越是光辉伟大。“群众看到元首始终是生活朴素、态度谦逊,对他一直高度信任。因此人们以最真挚热诚的方式庆祝元首的生日。”柏林警察局长在1935年5月如此说道。</p>
<p>[39]“金雉鸡”是第三帝国时期老百姓对纳粹党高官和高级将领的一种戏谑的称呼,因为他们的制服非常富丽堂皇。</p>
<hr>
<p>在20世纪30年代后半期,有两个新发展使得这种国内政治问题大大缓和了。首先,与纳粹政府内政外交的辉煌成就相比,腐败在民众心目中根本算不得什么重要问题;贪污腐败和结党营私被认为是一个总的来讲非常成功的政权的阴暗面,受到容忍。另外,群众对腐败行为渐渐习以为常,感觉也变得迟钝了。“人民对一切丑行都冷静超然地予以容忍,着实令人震惊。”社会民主党流亡理事会在1937年11月报告称,“从这种冷静超然,我们可以看出,道德已经沦丧到了什么程度。很多群众对任人唯亲和贪污腐败已经甘心容忍。”有些上了年纪的人对腐败的愤怒已经不能被较年轻的人所理解。群众听天由命的基本态度在“民不告,官不管”这句话中体现得淋漓尽致。记者雷蒙德·普雷策尔(化名塞巴斯蒂安·哈夫纳)在30年代末得出结论,人民已经完全领悟了官方对腐败话题的禁忌:</p>
<blockquote>
<p>由于纳粹领导人的贪腐数额极大,困惑的德国公众已经不用正常的名字称呼这种行为了。这些强盗是些大土匪,已经摇身一变成了权势炙手可热的大老爷。他们的权力极大,又极其厚颜无耻,人们不是为遭到抢劫而感到愤慨,倒是要庆幸,自己的东西还没有被抢光。</p>
</blockquote>
<p>30年代后半期经济的蓬勃发展是群众的谅解和容忍态度的另一个重要原因。在经济危机的凄惨岁月之后,群众对富丽堂皇的装扮并不感到反感,在某种程度上还认为这是富足生活和新德国的强大国威的恰当体现,对其表示欢迎。否则,我们就无法解释,奢侈成癖、腐化堕落的赫尔曼·戈林为什么毋庸置疑地受到群众爱戴了。他和他的妻子,曾经是演员的埃米·松内曼,满足了老百姓“追星”的需求。
1941年底1942年初,群众对腐败无动于衷地容忍甚至是接受的阶段结束了,让位于一种敏感。德军在莫斯科城下的失败、盟军开始集中轰炸德国城市,以及粮食供应的缩减,使得群众发出了“极其激烈的不满呼声”,同时人们也更加抱怨领导人享用的“外交官配给”。亚诺夫斯基和内特林那样的案件如果是在30年代肯定不会引起多少注意,现在却能引起群众的高度关注和一连几周的激烈讨论。
工人以激烈的言辞表达了对“民族共同体”内不同阶层承受战争苦难的程度不同和享受的生活条件不平等的不满。例如,一名工人对内特林案评论道:“我们希望终有一天能看到,对待那些大佬们也像对待平头百姓一样,否则的话,这个国家就要被冰雹砸得千疮百孔了。”党卫军保安处报告称,“群众对领导阶层的腐败现象越来越关注”。群众对当时的局面概括如下:“打死苍蝇,放走老虎。非常大的老虎不仅不怕被打,还能吃到更多肉。”</p>
<hr>
<p>政府领导层对群众的怨言的应对方法就是,通过象征性地、展示性地查处若干官员来安抚群众。早在纳粹统治的早期,政府就一直是这么做的,治标不治本,目标仅仅是安抚一下群众,而不会造成什么体制性的影响,因为那样的影响有可能会危及整个统治系统。但出现了一个新现象:在纳粹党内部,也有人表示出对腐败的不满了。尤其是在斯大林格勒的惨败之后,很多党员不再对贪污腐败和骄奢淫逸的行为无动于衷了。</p>
<hr>
<h3 id="结束语">结束语</h3>
<p>近期关于迫害犹太人的纳粹机构的研究突出地表明,纳粹统治下的很多“官僚系统”的特点是,将世界观的信仰与不受任何限制的行为方式结合了起来。权力监管的缺失使得纳粹党人得以不受阻挠地谋取私利、掠夺受害者的物质财富。尤其是腐败现象让我们感到,将迫害犹太人的机构描述为经典的“官僚机器”的做法,是值得商榷的,这种描述与其说是澄清了这些机构的特征,倒不如说是让它愈发难解了。</p>
<hr>
<p>第三帝国的反腐斗争的最大特点是专横霸道和随意任性。很多“达官贵人”由于自己的地位和政治靠山的保护,可以为所欲为,而下级官员在逾矩时却要面对极其严厉的处罚。于是,就出现了遭到打击的腐败、受到容忍的腐败和体制化的腐败三者并存的怪现状,而且这三者之间的界线也是有流动性的。对于某个腐败案件是否要进行查处,首先取决于这么做在政治上是否有利。普通法庭和党内法庭都是“元首国家”的没有独立性的机关,无法实施有效的司法诉讼。但在第三帝国,统治集团内部的臭名昭著的派系斗争却能带来一定程度的腐败监管,因为这种斗争常常是由于各派系互相指责对方腐败而展开的。
在第三帝国体制化的腐败的顶端,是希特勒本人。他通过赠礼、优待和资助的体制,来额外地巩固自己魅力十足的地位,他的玩世不恭的统治手段以身边人的道德败坏为基础。他努力通过物质手段,将其他领导人拴牢,但这并不能证明纳粹统治系统所谓的独裁特征。“希特勒体制”并非凌驾于数量众多的恩主—门客结构之上,而是与其在同一个层面上共存,这些结构在纳粹体制中是横向发展的。在这方面最突出的是各省的“诸侯”们,他们一般都控制着完善的小金库和基金会的系统,这些系统既不受纳粹党总财务官的监管,也不受国家中央权力的控制。虽然希特勒的权力足够强大,地位足够巩固,能够约束住腐败的封疆大吏们,但是元首在面对腐败问题时却非常冷漠(这很能说明问题),即便罪恶滔天的封臣也能保住自己的位子。</p>
<hr>
<p>在纳粹统治集团的上层,腐败不仅仅是狭义的物质财富来源。很多纳粹高级领导人拥有庄园和猎区,还收藏艺术品,他们这是在模仿贵族的生活方式。在获取这些表明身份地位的身外之物的过程中,他们往往杀人越货、胡作非为。他们的骄奢淫逸的生活方式——赫尔曼·戈林是其极端形式的代表——在外观上标示了1933年后精英集团的变化,强调了纳粹党人对社会的领导权,并昭然地突出各自在第三帝国统治集团内的地位。</p>
<hr>
<p>纳粹体制的管理不善和效率低下的例子不胜枚举,因此说纳粹政权进行了有意识的“现代化”的说法是站不住脚的。
但另一方面,我们面对着这样的问题:我们真的可以用传统的效率标准来评价纳粹政权吗?这种标准对于纳粹政权会不会完全无效呢?在纳粹统治下,货币本来就没有什么作用,政权靠借贷生存,借以开拓资源的则是最原始的手段——掠夺。纳粹政权劫掠和收集大量资产并将其投入灭绝机器的“工作效率”是极高的,也取得了骇人听闻的“成果”。在这样的体制中,腐败造成的高成本和收入亏空不是那么引人注目。在纳粹党人看来,腐败有时降低了效率、破坏了政府机能,但有时却是政治上的朋党体制的“润滑剂”,因此起到了推动政府运转和稳定全局的作用。另外,腐败鼓动更多人加入到“雅利安化”、大屠杀和剥削占领区的活动中。虽然德国群众对腐败进行了大规模的口诛笔伐,但德国社会的确是通过腐败获得了很多好处。
如果我们不把纳粹统治视为自上而下的独裁政权,而把它看作德国社会以各种方式广泛参与的社会行为,那么我们就会看到,腐败将纳粹统治和德国社会紧密交织起来,很多“普通的德国人”也通过中饱私囊参与到了纳粹的压迫和灭绝政策中来。</p>
<hr>
<h3 id="注释">注释</h3>
<p>[11]奥革阿斯是希腊神话中的埃利斯国王,太阳神赫利俄斯之子,拥有大批牲畜。欧律斯透斯要求赫拉克勒斯完成的十二项功绩之一就是在一天之内清理奥革阿斯的牲口圈,奥革阿斯也答应将他牲畜的十分之一作为报酬送给赫拉克勒斯。赫拉克勒斯挖掘沟渠,将阿尔普斯河和佩纽斯河(一说是两者之一)的河水引来,冲洗牲口圈,完成了任务。奥革阿斯反悔,拒绝给赫拉克勒斯牲畜,于是赫拉克勒斯杀死了奥革阿斯及其儿子们。因传说奥革阿斯的牛圈三十年从未打扫,污秽不堪,所以在西方常以“奥革阿斯的牛圈”来形容“最肮脏的地方或者积累成堆的难以解决的问题”</p>
<hr>
<p>以上摘自:
<img src="https://ooo.0o0.ooo/2016/12/04/58442798f0d49.jpg" alt="《纳粹德国的腐败与反腐》">
《纳粹德国的腐败与反腐》<br>
作者:(德)弗兰克·巴约尔<br>
译者: 陆大鹏<br>
出版社:译林出版社</p>
Linux常用基本命令指北
https://acuario.xyz/posts/how-to-use-linux/
2023-09-27T18:25:39+00:00
2016-10-30T02:47:50+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="废话">废话</h2>
<p>学习任何一种新东西,最好的方式就是进行实践。对于一个被 Windows 这样的 GUI OS 惯坏了的用户而言,上手 Linux 的最快途径便是利用一些现成的项目进行实操。正如笔者肤浅的 Linux 使用技能完完全全是靠自己在 VPS 上搭梯子(ss)达成的。在这里写一些基本命令的笔记,一方面方便自己今后查阅,另外也给看到本文的 Linux 小白一些入(bu)门(kao)级(pu)的指北。</p>……
<h2 id="废话">废话</h2>
<p>学习任何一种新东西,最好的方式就是进行实践。对于一个被 Windows 这样的 GUI OS 惯坏了的用户而言,上手 Linux 的最快途径便是利用一些现成的项目进行实操。正如笔者肤浅的 Linux 使用技能完完全全是靠自己在 VPS 上搭梯子(ss)达成的。在这里写一些基本命令的笔记,一方面方便自己今后查阅,另外也给看到本文的 Linux 小白一些入(bu)门(kao)级(pu)的指北。</p>
<h2 id="linux-的历史">Linux 的历史</h2>
<p>关于 GNU/Linux 的相关历史,<a href="http://www.jianshu.com/p/a6a594a00b5b">GNU/Linux与开源文化的那些人和事</a> 一文已经有很详尽的介绍。简单来说,Linux 是 Linus Torvalds 在 1991 年凭个人兴趣爱好发明的一个轮子。在众多开发者和社区的贡献下这个轮子逐渐变得众人皆知。
<img src="https://ooo.0o0.ooo/2016/10/29/5814ef387a70f.png" alt="Unix发展过程图">
(Source:<a href="http://www.jianshu.com/p/a6a594a00b5b">刘军民</a>)</p>
<p>GNU/Linux 存在很多发行版,最早发布 GNU/Linux 系统的公司是 Redhat,现在诸如 Debian、Ubuntu、CentOS 等等的系统都是被广泛使用的 GNU/Linux 发行版。Ubuntu 在营销和 GUI 优化方面做的更好一些,所以我们偶尔能看到 Ubuntu 出现在普通消费者新购电脑的预装系统中。</p>
<h2 id="了解命令提示符和命令行">了解命令提示符和命令行</h2>
<h3 id="命令提示符和命令行">命令提示符和命令行</h3>
<p><img src="https://ooo.0o0.ooo/2016/10/29/5814ef25a7472.png" alt="命令提示符和命令行">
(Source:<a href="http://www.cnblogs.com/xpjiang/p/5089137.html">姜鹄</a>)</p>
<h3 id="shell-简介">Shell 简介</h3>
<p><a href="https://zh.wikipedia.org/zh-cn/%E6%AE%BC%E5%B1%A4">Shell</a> 指「为用户提供用户界面」的软件,通常指的是命令行界面的解析器。泛指所有为用户提供操作界面的程序,也就是程序和用户交互的层面。在 Linux 系统中,我们使用的是 Linux Shell 进行操作,不同版本的 Linux 搭配了不同版本的 Shell,在使用上语法有所差异。bash 是 Unix shell 的一种,一般来说目前绝大多数的 Linux 都支持 bash。下面我们以 bash 为例介绍一下 shell 的命令。</p>
<p>所谓命令行操作,可以理解为人机交互通过一条一条的命令来实现。bash shell 的命令格式为:</p>
<pre tabindex="0"><code>command [options] [arguments]
</code></pre><p>其中,
command:表示命令的名称。
options:表示命令的选项。
arguments:表示命令的参数。</p>
<p>我们一般把具有以上格式的字符串称为命令行。命令行是用户与 shell 之间对话的基本单位。
命令的选项是包含一个或多个字母的代码,主要用于改变命令的执行方式。在选项前面有一个 <code>-</code> 符号,用于区别参数。例如:</p>
<pre tabindex="0"><code>[root@WEBServer ~]$ ls -a ~/test
</code></pre><p>上面的语句中:
<code>[root@WEBServer ~]$</code> 为<strong>命令提示符</strong>,<code>root</code> 为用户名,<code>WEBServer</code> 为本机名,<code>~</code> 为当前的工作目录;
<code>ls -a ~/test</code> 为<strong>命令行</strong>,<code>ls</code> 为命令名称,<code>a</code> 为命令选项,<code>~/test</code> 为命令参数。</p>
<p>命令行的命令选项可以不区分前后顺序地同时列出,例如:</p>
<pre tabindex="0"><code>[root@WEBServer ~]$ ls -la
[root@WEBServer ~]$ ls -al
</code></pre><p>还有很多 shell 的具体细节本文暂时不表,你可以通过 <a href="http://www.epubit.com.cn/article/412">这篇文章</a> 来进行学习。后文将省略命令提示符,只给出命令行。</p>
<h3 id="shell-管道">Shell 管道</h3>
<p>所谓管道,顾名思义具有连接的作用。我们可以通过管道把一个命令的输出当作下一个命令的输入,使用管道符 <code>|</code> 把第 1 个命令的输入当作第 2 个命令的输出,第 2 个命令的输出当作第 3 个命令的输入,依此类推。例如:</p>
<pre tabindex="0"><code>ps aux | grep blabla | wc –l
</code></pre><p>上面这个命令由三个命令组成,
<code>ps aux</code> 用于查看系统中正在运行的进程
<code>grep blabla</code> 用于匹配(提取)包含字段为 blabla 的文本信息
<code>wc –l</code> 用于统计文本的数量
使用管道连接后,整条命令的作用就是查看系统中正在运行的名为 blabla 的进程数量。</p>
<h2 id="常用快捷键">常用快捷键</h2>
<p>自动补全命令:<code>Tab</code>
停止当前命令:<code>Ctrl</code>+<code>C</code>
键盘输入结束:<code>Ctrl</code>+<code>D</code></p>
<h2 id="包管理">包管理</h2>
<h3 id="常见包管理套件">常见包管理套件</h3>
<p>Linux 不是 GUI OS,几乎所有操作都需要输入命令行实现。所以为了方便地安装 / 卸载软件等操作,Linux 内置了专门用于对软件包进行管理的工具。不同版本的 Linux 系统使用不同的 <a href="https://www.ibm.com/developerworks/cn/linux/l-cn-rpmdpkg/">软件包管理</a> 指令。</p>
<p><img src="https://chusiang.gitbooks.io/working-on-gnu-linux/content/imgs/2013-09-21-pms.png" alt="各版本系统常见套件管理指令">
(Source:<a href="https://chusiang.gitbooks.io/working-on-gnu-linux/content/04.package-management.html">凍仁翔</a>)</p>
<p>根据上图,你可以实现对软件包的基本操作。例如,apt 常用命令如下:</p>
<pre tabindex="0"><code>sudo apt-get update #更新源索引
sudo apt-get install <package> #安装软件 <package>
sudo apt-get remove <package> #卸载软件 <package>
sudo apt-get upgrade #将系统中所有软件升级到最新版本
sudo apt-get remove <package> #卸载软件 <package>
</code></pre><h3 id="centos-相关包管理套件介绍">CentOS 相关包管理套件介绍</h3>
<p>笔者使用的是 Linux 发行版本是 CentOS 6,在此简单介绍一下 CentOS 的相关包管理套件。从上面的各版本系统常见套件管理指令中我们看到 CentOS 使用 rpm 和 yum 进行包管理。</p>
<p><strong>RPM</strong> (RPM Package Manager) 虽有 RedHat 的标志,但其原始设计理念是开放式的,包括 OpenLinux、S.u.S.E. 以及 Turbo Linux 等 Linux 的分发版本都有采用。</p>
<p><strong>YUM</strong> (Yellow dog Updater, Modified) 是杜克大学为了提高 RPM 软件包安装性而开发的一种软件包管理器。</p>
<h3 id="yum-源和-epel">YUM 源和 EPEL</h3>
<h4 id="源">源</h4>
<p>软件包管理器就像 PC 上的各种软件管家,软件包管理器的不同『源』收录的软件资源 / 信息是不同的,如当我们使用 yum 安装一个软件 <code><ooxx></code> 时返回的信息是:</p>
<pre tabindex="0"><code>No package <ooxx> available.
Error: Nothing to do
</code></pre><p>这有可能是因为我们使用的『源』中并没有记录关于 <code><ooxx></code> 的信息。所以我们需要换一个信息丰富的『源』来解决这个问题。</p>
<h4 id="epel-及使用方法">EPEL 及使用方法</h4>
<p>EPEL (Extra Packages for Enterprise Linux) 是 Fedora 团队的免费、开源项目,用于为 RedHat 系的 Linux 系统提供额外的软件包,其适用于 RHEL、CentOS 和 Scientific Linux。对于没有默认使用 EPEL 作为 YUM 源的 CentOS,我们需要安装、设置 EPEL 后才能正常使用:</p>
<ol>
<li>使用 Root 身份登录 Linux</li>
<li>执行如下命令确认自己的系统版本,如返回信息为 <code>CentOS release 6.8 (Final)</code> 则表示系统版本为 <code>CentOS 6</code>。</li>
</ol>
<pre tabindex="0"><code>head -n 1 /etc/issue
</code></pre><ol start="3">
<li>执行如下命令确认自己的系统内核,如返回信息为 <code>Linux <username> 2.6.32-042stab117.16 #1 SMP Fri Sep 9 21:57:19 MSK 2016 x86_64 x86_64 x86_64 GNU/Linux</code> 则表示系统内核为 <code>64 Bit</code>。(<code>x86</code> 为 <code>32 Bit</code>)</li>
</ol>
<pre tabindex="0"><code>uname -a
</code></pre><ol start="4">
<li>根据系统版本和内核选择如下命令执行:
***RHEL/CentOS 7 ***</li>
</ol>
<pre tabindex="0"><code>yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
</code></pre><p><em><strong>RHEL/CentOS 6</strong></em></p>
<pre tabindex="0"><code>yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
</code></pre><ol start="5">
<li>
<p>执行命令 <code>yum repolist</code> 确认 EPEL 仓库已经安装</p>
</li>
<li>
<p>需要使用 EPEL 安装软件 <code><software></code> 时,执行如下命令即可:</p>
</li>
</ol>
<pre tabindex="0"><code>yum --enablerepo=epel install <software>
</code></pre><h2 id="系统">系统</h2>
<pre tabindex="0"><code>whatis <command> #单行描述命令
man <command> #显示命令手册
alias <alias>="<command>" #设置 <command> 命令的别名为 <alias>,
之后执行 <alias> 命令相当于执行 <command> 命令
date #显示日期
cal #显示日历
shutdown -r now #关机后重启
shutdown -h now #关闭系统服务后关机
shutdown -h 10 #10min 后关闭系统服务后关机
shutdown -h 21:25 #10min 后关闭系统服务后关机
reboot #立即重启
init 0 #关机
init 6 #重启
free #显示系统内存状态
uname -a #查看系统信息
head -n 1 /etc/issue #查看版本信息
lsb_release -a #查看版本信息
df -h #查看磁盘空间
du -sh #查看目录大小
clear #清除屏幕信息
</code></pre><h2 id="文件">文件</h2>
<h3 id="常用参数">常用参数</h3>
<pre tabindex="0"><code>-r #递归,操作某目录及其子目录中的文件时使用
-i #交互操作,操作前会询问
-f #强制操作,不进行提示
-help #显示帮助信息
</code></pre><h3 id="常用命令">常用命令</h3>
<pre tabindex="0"><code>wget <URL> #下载 <URL> 指向的文件
pwd #显示当前所在目录
mkdir <dir> #创建新目录
mkdir -m <access_code> <dir> #创建新目录并设定目录权限
mkdir -p <dir>/<dir> #创建新目录,若无父目录,则创建
rmdir <dir> #删除空目录
rmdir -p <dir>/<dir> #删除空目录及父目录中的所有空目录
cp -p <source> <target> #复制文件 / 目录 <source> 及其属性到 <target>
cp -r <source> <target> #递归复制文件 / 目录 <source> 内所有内容到 <target>
cp -a <source> <target> #相当于 cp -pdr
cp -i <source> <target> #复制文件时若目标文件存在,则询问操作
rm -f <file> #强制移除文件
rm -r <file> #递归移除文件 / 目录(慎用)
mv <file> <dir> #移动文件 <file> 到目录 <dir>
mv <file> <new> #重命名文件 <file> 为 <new>
cat <file> #显示文件内容
cat -b <file> #显示文件内容,空白行不显示行号
cat -n <file> #显示文件内容,显示所有行号
more <file> #分页显示文件内容
空格(Space) #下一页
回车(Enter) #下一行
/<string> #向下搜索内容 <string>
:f #显示文件名及行数
q #关闭 more 显示
less <file> #分页显示文件内容
PageUp #上一页
PageDown #下一页
空格(Space) #下一页
?<string> #向上搜索内容 <string>
/<string> #向下搜索内容 <string>
q #关闭 less 显示
tail <file> #显示文件最后 10 行内容
tail -n <num> <file> #显示文件最后 <num> 行内容
touch <file> #若 <file> 不存在,则新建文件 <file>
#若 <file> 存在,则修改 <file> 的时间(atime/ctime/mtime)为当前时间
touch -t <date> <file> #修改 <file> 的时间为指定 <date> 时间(YYMMDDhhmm)
whereis <file> #查找文件 <file>
locate <keyword> #查找文件(目录)名包含 <keyword> 的文件(目录)
find <path> <file> #在 <path> 路径下查找文件 <file>
tar -zxvf <file>.gz <dir> #打包 <dir> 目录并压缩为 <file>.gz
tar -zxvf <file>.gz #解压缩解包文件 <file>.gz
tar -jxvf <file>.bz2 <dir> #打包 <dir> 目录并压缩为 <file>.bz2
tar -jxvf <file>.bz2 #解压缩解包文件 <file>.bz2
</code></pre><h3 id="编辑文件">编辑文件</h3>
<p>编辑文本时我们可以使用 <code>vi</code> 或 <code>vim</code> 工具来实现,直接执行命令即可编辑文件 <code><file></code>:</p>
<pre tabindex="0"><code>vi <file>
</code></pre><p>编辑文件时有三种命令模式:命令模式、插入模式、编辑模式。使用 <code>ESC</code> 或 <code>i</code> 或 <code>:</code> 来切换模式。命令模式下(按 <code>ESC</code> 进入):</p>
<pre tabindex="0"><code>:q #询问退出
:q! #不保存并强制退出
:wq #保存并退出
:set number #显示行号
:set nonumber #隐藏行号
/apache #在文档中查找 apache 按 n 跳到下一个,shift+n 上一个
yyp #复制光标所在行,并粘贴
j #下一行,相当于↓
k #上一行,相当于↑
h #左移一个字符,相当于←
l #右移一个字符,相当于→
</code></pre><p>其实这已经算是 <a href="https://zh.wikipedia.org/wiki/Vi">vi</a>/<a href="https://zh.wikipedia.org/wiki/Vim">Vim</a> 的使用方法(命令)了,可以通过 <a href="https://zhuanlan.zhihu.com/p/21278816">这篇文章</a> 入门。</p>
<h3 id="清空文件内容">清空文件内容</h3>
<p>下面的三个命令都可实现清空文件内容,但命令执行后文件大小有所不同:</p>
<pre tabindex="0"><code>echo "" > <file> #文件大小被截为 1 字节
> <file> #文件大小被截为 0 字节
cat/dev/null > <file> #文件大小被截为 0 字节
</code></pre><h3 id="文件权限">文件权限</h3>
<h4 id="linux-文件权限的表示">Linux 文件权限的表示</h4>
<p>使用 <code>ll</code> 命令查看当前目录下的文件详细信息,文件属性如图所示:
<img src="https://cloud.githubusercontent.com/assets/7871813/17443279/560334cc-5b6c-11e6-9bbc-0017890d80aa.png" alt="Linux文件属性">
(Source:<a href="https://github.com/dwqs/blog/issues/30">dwqs</a>)</p>
<p>Linux 系统中的文件有三种基本权限,使用这三种权限的数值组合可以满足文件权限管理的所有需求。</p>
<table>
<thead>
<tr>
<th>参数</th>
<th>意义</th>
<th>数值</th>
</tr>
</thead>
<tbody>
<tr>
<td>R</td>
<td>读(read)</td>
<td>4</td>
</tr>
<tr>
<td>W</td>
<td>写(write)</td>
<td>2</td>
</tr>
<tr>
<td>X</td>
<td>可执行(execute)</td>
<td>1</td>
</tr>
</tbody>
</table>
<p><img src="https://cloud.githubusercontent.com/assets/7871813/17443291/64c1cf3c-5b6c-11e6-8dd6-5b3a371e13eb.png" alt="文件权限">
(Source:<a href="https://github.com/dwqs/blog/issues/30">dwqs</a>)</p>
<p>文件属性中 <code>drwxr-x---</code> 为 <code>fonts</code> 文件夹的权限
<code>drwxr-x---</code> 一共十个字符,分成四段:
第一个字符表示文件属性,<code>-</code> 表示普通文件,<code>d</code> 表示目录,<code>l</code> 表示链接。
第二三四个字符 <code>rwx</code> 表示当前所属用户的权限。数值表示为 4+2+1=7
第五六七个字符 <code>r-x</code> 表示当前所属组的权限。数值表示为 4+0+1=5
第八九十个字符 <code>---</code> 表示其他用户权限。数值表示为 0+0+0=0
故 <code>fonts</code> 文件夹的权限用数值表示为 750</p>
<h4 id="更改权限">更改权限</h4>
<pre tabindex="0"><code>chgrp -r <file> #更改文件所属用户组
chown -r <user>:<group> <file> #更改文件所属用户
</code></pre><p><code>chmod</code> 命令可更改文件权限,其有 4 个参数</p>
<ul>
<li>指定用户及用户组:<code>[u <指定用户> g <指定用户组> o <其他用户> a <所有用户>]</code></li>
<li>权限增减:<code>[+ 增加权限 - 减少权限]</code></li>
<li>权限变更内容:<code>[r w x]</code></li>
<li>权限变更的文件名: <code><file></code></li>
</ul>
<p>文件 newfile 的权限为 <code>-rw-r—-x</code>,如需将其权限更改为 <code>-rwxrw-r-x</code>(数值表示为 765),执行下列任意一条命令即可:</p>
<pre tabindex="0"><code>sudo chmod u+x,g+w,o+r newfile
sudo chmod 765 newfile
</code></pre><h2 id="进程">进程</h2>
<pre tabindex="0"><code>top #实时显示进程信息
ps aux #显示进程信息
ps aux | grep <package> #显示 <package> 程序的进程信息
kill <PID> #终止 PID 为 <PID> 的进程
kill -2 <PID> #中断进程,类似 Ctrl+C
kill -9 <PID> #杀死进程
</code></pre><table>
<thead>
<tr>
<th><code>top</code> 表头</th>
<th>含义</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>PID</td>
<td>进程 ID</td>
<td></td>
</tr>
<tr>
<td>USER</td>
<td>进程的属主</td>
<td></td>
</tr>
<tr>
<td>PR</td>
<td>优先级</td>
<td></td>
</tr>
<tr>
<td>NI</td>
<td>Nice 值</td>
<td>负值表示高优先级<br>正值表示低优先级</td>
</tr>
<tr>
<td>VIRT</td>
<td>虚拟內存使用量</td>
<td>单位 KB</td>
</tr>
<tr>
<td>RES</td>
<td>固定內存使用量</td>
<td>单位 KB</td>
</tr>
<tr>
<td>SHR</td>
<td>共享内存大小</td>
<td>单位 KB</td>
</tr>
<tr>
<td>S</td>
<td>进程状态</td>
<td><code>D</code> 不可中断的睡眠状态<br><code>R</code> 运行<br><code>S</code> 睡眠<br><code>T</code> 跟踪 / 停止<br><code>Z</code> 僵尸进程</td>
</tr>
<tr>
<td>%CPU</td>
<td>CPU 占比</td>
<td></td>
</tr>
<tr>
<td>%MEM</td>
<td>内存占比</td>
<td></td>
</tr>
<tr>
<td>TIME+</td>
<td>进程实际使用 CPU 运作的时间</td>
<td>单位 1/100 秒</td>
</tr>
<tr>
<td>COMMAND</td>
<td>程序的实际指令</td>
<td></td>
</tr>
</tbody>
</table>
<hr>
<table>
<thead>
<tr>
<th><code>ps aux</code> 表头</th>
<th>含义</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>USER</td>
<td>进程的属主</td>
<td></td>
</tr>
<tr>
<td>PID</td>
<td>进程 ID</td>
<td></td>
</tr>
<tr>
<td>%CPU</td>
<td>CPU 占比</td>
<td></td>
</tr>
<tr>
<td>%MEM</td>
<td>内存占比</td>
<td></td>
</tr>
<tr>
<td>VSZ</td>
<td>虚拟內存使用量</td>
<td>单位 KB</td>
</tr>
<tr>
<td>RSS</td>
<td>固定內存使用量</td>
<td>单位 KB</td>
</tr>
<tr>
<td>TTY</td>
<td>在哪个终端机上面运作</td>
<td><code>?</code> 与终端机无关<br><code>tty1-tty6</code> 本机登入者程序<br><code>pts/0</code>由网络连接进主机的程序</td>
</tr>
<tr>
<td>STAT</td>
<td>当前程序状态</td>
<td><code>D</code> 无法中断的休眠状态(通常 IO 的进程)<br><code>R</code> 正在运行可中在队列中可过行的<br><code>S</code> 处于休眠状态<br><code>T</code> 停止或被追踪<br><code>W</code> 进入内存交换 (从内核 2.6 开始无效)<br><code>X</code> 死掉的进程 (基本很少見)<br><code>Z</code> 僵尸进程<br><code><</code> 优先级高的进程<br><code>N</code> 优先级较低的进程<br><code>L</code> 有些页被锁进内存<br><code>s</code> 进程的领导者(在它之下有子进程)<br><code>l</code> 多进程的(使用 CLONE_THREAD, 类似 NPTL pthreads)<br><code>+</code> 位于后台的进程组</td>
</tr>
<tr>
<td>START</td>
<td>进程触发启动的时间</td>
<td></td>
</tr>
<tr>
<td>TIME</td>
<td>进程实际使用 CPU 运作的时间</td>
<td>单位秒</td>
</tr>
<tr>
<td>COMMAND</td>
<td>程序的实际指令</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="用户">用户</h2>
<pre tabindex="0"><code>useradd -m <user> #添加用户 <user>
passwd <user> #设置用户 <user> 的密码
userdel -r <user> #删除用户 <user>
su <userB> #临时切换到 <userB> 身份工作,运行 `exit` 命令返回
groups #查看当前用户所属的组
usermod -G <group> <user> #将用户 <user> 加入 <group> 组
usermod -g <group> <user> #将用户 <user> 加入 <group> 组,并从原有用户组中除去
</code></pre><h2 id="网络">网络</h2>
<h3 id="常用命令-1">常用命令</h3>
<pre tabindex="0"><code>netstat -tunpl #列出所有监听的服务端口
iptables -L -n #查看防火墙设置
iptables -F #清空防火墙规则
ifconfig -a |grep -i hw #查看 MAC 地址
ifconfig | awk '/eth/{print $1,$5}' #查看 MAC 地址
sudo lshw -c network | grep serial #查看 MAC 地址
</code></pre><h3 id="添加指定端口的防火墙例外">添加指定端口的防火墙例外</h3>
<p>添加指定端口 <code><port></code> 的防火墙例外使用如下命令:</p>
<pre tabindex="0"><code>iptables -A INPUT -p tcp --dport <port> -j ACCEPT
</code></pre><h3 id="简单的-http-服务">简单的 HTTP 服务</h3>
<p>搭建一个简单的 Web Server,使用 HTTP 服务将 <code><http_dir></code> 中的目录和文件以 HTTP 的方式展示出来:</p>
<pre tabindex="0"><code>cd /<http_dir> && python -m SimpleHTTPServer <port>
</code></pre><p>若本机的外网 IP 为 <code><IP></code>,使用浏览器访问 <code>http://<IP>:<port></code> 即可浏览 <code><http_dir></code> 目录。这是一个可以用来共享文件的非常有用的方式。</p>
<h2 id="qa">Q&A</h2>
<h3 id="设置开机启动">设置开机启动:</h3>
<h4 id="开机启动命令">开机启动命令</h4>
<pre tabindex="0"><code>vi /etc/rc.local
</code></pre><p>将开机启动命令写入上述文件即可。</p>
<h4 id="开机启动服务">开机启动服务</h4>
<pre tabindex="0"><code>chkconfig --list 显示开机可以自动启动的服务
chkconfig --add 添加开机自动启动 *** 服务
chkconfig --del 删除开机自动启动 *** 服务
setup 在 shell 的 GUI 中进行详细配置
ntsysv 在 shell 的 GUI 中进行简单配置
</code></pre><h3 id="修改-ssh-默认端口">修改 SSH 默认端口</h3>
<p>SSH 默认端口一般为 <code>22</code>,可通过修改配置文件自定义 SSH 默认端口:</p>
<pre tabindex="0"><code>vi /etc/ssh/sshd_config
</code></pre><p>修改文件中 <code>#Port <port></code> 的 <code><port></code> 为自定义的端口,并删除 <code>#</code> 使之生效。</p>
<h3 id="限制-ssh-登录的-ip">限制 SSH 登录的 IP</h3>
<p>如需限制指定 <code><IP></code> 使用 SSH 登录,可编辑文件实现:</p>
<pre tabindex="0"><code>vi /etc/hosts.deny
</code></pre><p>文件末尾加入 <code>sshd:ALL</code></p>
<pre tabindex="0"><code>vi /etc/hosts.allow
</code></pre><p>文件末尾加入 <code>sshd:<IP></code></p>
<h2 id="参考链接">参考链接</h2>
<p><a href="http://www.jianshu.com/p/a6a594a00b5b">GNU/Linux 与开源文化的那些人和事</a>
<a href="https://chusiang.gitbooks.io/working-on-gnu-linux/content/">完全用 GNU/Linux 工作</a>
<a href="http://blog.csdn.net/xiaoguaihai/article/details/8705992">【Linux】linux 常用基本命令</a>
<a href="http://www.cnblogs.com/xpjiang/p/5089137.html">九十分钟极速入门 Linux——Linux Guide for Developments 学习笔记</a>
<a href="http://linuxtools-rst.readthedocs.io/zh_CN/latest/index.html">Linux 工具快速教程</a>
<a href="https://github.com/dwqs/blog/issues/30">Linux 的文件权限</a>
<a href="http://coolshell.cn/articles/1480.html">非常简单的Python HTTP服务</a>
<a href="http://www.epubit.com.cn/article/412">Linux 常用命令及使用技巧</a>
<a href="https://zhuanlan.zhihu.com/p/21278816">vim/vi 命令整理</a></p>
ShadowsocksR简明教程
https://acuario.xyz/posts/how-to-use-shadowsocks-rss/
2023-09-27T18:25:39+00:00
2016-10-22T22:50:46+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>简明教程系列:
<a href="https://acuario.xyz/how-to-use-shadowrocket/">Shadowrocket 简明教程</a>
<a href="https://acuario.xyz/how-to-use-ssr-android/">SSR for Android 简明教程</a></p>
<hr>
<p>在网上看到的软件配置教程都不够满意,特此成文帮助使用 shadowsocks-rss for Windows 的朋友快速上手。</p>……
<p>简明教程系列:
<a href="https://acuario.xyz/how-to-use-shadowrocket/">Shadowrocket 简明教程</a>
<a href="https://acuario.xyz/how-to-use-ssr-android/">SSR for Android 简明教程</a></p>
<hr>
<p>在网上看到的软件配置教程都不够满意,特此成文帮助使用 shadowsocks-rss for Windows 的朋友快速上手。</p>
<p>把大象放进冰箱只需三步:</p>
<ol>
<li>开门:添加服务器信息(可手动添加或扫码或链接添加)</li>
<li>把大象放进去:设置系统代理模式并更新代理规则</li>
<li>关门:连接代理</li>
</ol>
<h2 id="添加服务器信息">添加服务器信息</h2>
<p>程序运行后将自动在系统托盘(桌面右下角,与 QQ 等软件在一起)后台运行,可右击软件图标,扫描屏幕中显示的<strong>二维码添加</strong>服务器配置,或复制服务器配置链接后选择其<strong>从剪贴板复制地址</strong>添加服务器配置</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b991ae4f82.png" alt="添加服务器信息"></p>
<p>也可以双击软件图标打开服务器配置页面进行修改或添加新的服务器配置,添加 / 修改后点击「确定」使配置生效</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b991b53ef1.png" alt="修改或添加服务器信息"></p>
<h2 id="设置代理规则和系统代理模式">设置代理规则和系统代理模式</h2>
<p>右击软件图标,在<strong>代理规则</strong>选项中选择「绕过局域网和大陆」。</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b99190bd72.png" alt="设置代理规则"></p>
<p>下载 <a href="https://softs.fun/Other/pac.txt">GFWList PAC文件</a>(右键 链接另存为...,如无法下载可使用<a href="https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/other/pac.txt">备用链接</a>),右击软件图标,在<strong>PAC</strong>选项中选择「编辑本地 PAC 文件」,在打开的窗口中使用下载下来的 <a href="https://softs.fun/Other/pac.txt">GFWList PAC文件</a> 替换已有的 pac.txt 文件。</p>
<p><img src="https://i.loli.net/2018/05/17/5afda04c0c79b.png" alt="更新 PAC 为 GFWList"></p>
<p>右击软件图标,<strong>系统代理模式</strong>选项中的默认选项是不修改系统(IE)代理,<strong>推荐</strong>选择「PAC 模式」可使系统中符合 GFWList (一个无法正常访问的网站列表)的网络连接通过代理进行连接。</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b9917e03f0.png" alt="默认不修改系统(IE)代理">
<img src="https://ooo.0o0.ooo/2016/10/22/580b991962bc3.png" alt="设置PAC模式"></p>
<p>右击软件图标,在<strong>系统代理模式</strong>选项中选择「全局模式」可使系统的所有网络连接通过代理进行连接。</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b991ad0ff6.png" alt="设置全局模式"></p>
<p>进行上述设置后代理自动生效,无需特殊开关。</p>
<h2 id="进阶使用">进阶使用</h2>
<p>仅仅只进行上述操作是远远不够的,在可以使用代理的情况下,我们推荐使用 <a href="https://www.google.com/chrome/browser/desktop/">Chrome 浏览器</a> 浏览网站。其可以使用特定插件进一步自定义的代理规则,方法如下:</p>
<h3 id="安装-chrome-插件">安装 Chrome 插件</h3>
<p>使用 Chrome 浏览器打开 <a href="https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=zh-CN">Proxy SwitchyOmega</a> 并安装该插件</p>
<h3 id="插件设置">插件设置</h3>
<p>插件安装后会出现在浏览器地址栏右侧(如下图),单击插件图标进入<strong>选项</strong>进行插件设置</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b991b2ee69.png" alt="Proxy SwitchyOmega"></p>
<p>新建情景模式 - 随意名称 - 创建代理服务器</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b9918cf4ce.png" alt="新建情景模式">
<img src="https://ooo.0o0.ooo/2016/10/22/580b9acc76fcb.png" alt="创建代理服务器"></p>
<p>选择刚刚创建的情景模式,代理协议 socks5,代理服务器 127.0.0.1,代理端口 1080,并应用选项</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b9accb760b.png" alt="设置代理服务器"></p>
<p>在遇到无法正常访问的网站时,单击插件图标,选择自己创建的代理服务器情景模式,刷新网页即可自动使用代理进行访问。</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b9acbdfcc0.png" alt="指定情景模式进行代理"></p>
<p>但是这样不够智能,还需要手动频繁切换,我们可使用<strong>自动切换</strong>情景模式。</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b9acc7acca.png" alt="自动切换情景模式进行代理"></p>
<p>在遇到无法正常访问的网站时,单击插件图标,<strong>添加条件</strong>,将弹出的设置窗口中情景模式设置为自己创建的代理服务器情景模式,刷新网页即可自动使用代理进行访问,且今后再次访问该网域也将自动使用该情景模式。类似的,不需要代理的网站可设置其情景模式为直接连接即可。</p>
<p><img src="https://ooo.0o0.ooo/2016/10/22/580b9acc7b8cf.png" alt="添加条件">
<img src="https://ooo.0o0.ooo/2016/10/22/580b9acd4767c.png" alt="添加特定网站的情景模式"></p>
Shadowrocket简明教程
https://acuario.xyz/posts/how-to-use-shadowrocket/
2023-09-27T18:25:39+00:00
2016-10-22T22:41:54+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>简明教程系列:
<a href="https://acuario.xyz/how-to-use-ssr-android/">SSR for Android 简明教程</a>
<a href="https://acuario.xyz/how-to-use-shadowsocks-rss/">ShadowsocksR 简明教程</a></p>
<hr>
<p>在网上看到的软件配置教程都不够满意,特此成文帮助使用小火箭的朋友快速上手。</p>……
<p>简明教程系列:
<a href="https://acuario.xyz/how-to-use-ssr-android/">SSR for Android 简明教程</a>
<a href="https://acuario.xyz/how-to-use-shadowsocks-rss/">ShadowsocksR 简明教程</a></p>
<hr>
<p>在网上看到的软件配置教程都不够满意,特此成文帮助使用小火箭的朋友快速上手。</p>
<p>把大象放进冰箱只需三步:</p>
<ol>
<li>开门:添加服务器信息(可扫码或手动添加)</li>
<li>把大象放进去:设置代理规则</li>
<li>关门:连接代理</li>
</ol>
<h2 id="添加服务器信息">添加服务器信息</h2>
<p>程序<strong>首页</strong>可扫描二维码添加服务器配置,或手动添加服务器配置
<img src="https://ooo.0o0.ooo/2016/10/22/580b57e4b1549.png" alt="程序首页"></p>
<p>手动添加服务器配置如下图所示
<img src="https://ooo.0o0.ooo/2016/10/23/580c4081ded4b.png" alt="手动添加服务器配置"></p>
<h2 id="设置代理规则">设置代理规则</h2>
<p>程序<strong>配置</strong>页添加代理规则配置
代理规则文件推荐使用:</p>
<pre tabindex="0"><code>https://raw.githubusercontent.com/lhie1/Rules/master/Shadowrocket.conf
</code></pre><p>联网状态下添加远程文件后该文件将自动下载至本地,确认使用刚刚添加的代理规则文件
<img src="https://ooo.0o0.ooo/2016/10/22/580b57e62e9d8.png" alt="03.png"></p>
<p>程序<strong>设置</strong>页选择全局路由为 <code>Config</code>
<img src="https://ooo.0o0.ooo/2016/10/22/580b57e4ad8dd.png" alt="04.png"></p>
<h2 id="连接代理">连接代理</h2>
<p>返回程序<strong>首页</strong>连接代理,系统弹出 VPN 连接权限通知时点击允许(Allow)。
<img src="https://ooo.0o0.ooo/2016/10/22/580b57e4af848.png" alt="05.png"></p>
SSR for Android简明教程
https://acuario.xyz/posts/how-to-use-ssr-android/
2023-09-27T18:25:39+00:00
2016-10-22T22:14:58+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>简明教程系列:
<a href="https://acuario.xyz/how-to-use-shadowrocket/">Shadowrocket 简明教程</a>
<a href="https://acuario.xyz/how-to-use-shadowsocks-rss/">ShadowsocksR 简明教程</a></p>
<hr>
<p>在网上看到的软件配置教程都不够满意,特此成文帮助使用 shadowsocks-rss for Android 的朋友快速上手。</p>……
<p>简明教程系列:
<a href="https://acuario.xyz/how-to-use-shadowrocket/">Shadowrocket 简明教程</a>
<a href="https://acuario.xyz/how-to-use-shadowsocks-rss/">ShadowsocksR 简明教程</a></p>
<hr>
<p>在网上看到的软件配置教程都不够满意,特此成文帮助使用 shadowsocks-rss for Android 的朋友快速上手。</p>
<p>把大象放进冰箱只需三步:</p>
<ol>
<li>开门:添加服务器信息(可手动添加或扫码或链接添加)</li>
<li>把大象放进去:设置代理规则和需要代理的程序</li>
<li>关门:连接代理</li>
</ol>
<h2 id="添加服务器信息">添加服务器信息</h2>
<p>程序<strong>首页</strong>可手动修改服务器信息,或点击 LOGO 进入服务器配置页面添加新的配置
<img src="https://ooo.0o0.ooo/2016/10/22/580b74ad75cea.png" alt="01.png"></p>
<p>通常扫描二维码或从剪贴板导入链接进行添加新的配置
<img src="https://ooo.0o0.ooo/2016/10/22/580b74ae78b35.png" alt="02.png"></p>
<p>添加成功后确认使用刚刚添加的服务器节点
<img src="https://ooo.0o0.ooo/2016/10/22/580b74ad6e90f.png" alt="03.png"></p>
<h2 id="设置代理规则和需要代理的程序">设置代理规则和需要代理的程序</h2>
<p>返回程序<strong>首页</strong>,路由选项选择绕过局域网和大陆网站。根据需要设置开机自动启动。并设置分应用代理。
<img src="https://ooo.0o0.ooo/2016/10/22/580b74ae26f0e.png" alt="04.png"></p>
<p>在<strong>分应用代理</strong>页面开启绕行模式,勾选所有不需要代理的 App,这将使开启代理后自动绕过这些不需代理的 App,而没有勾选的 App 和系统本身将通过代理进行连接。你亦可反向分应用代理,不开启绕行模式,勾选需要代理的特定 App 进行使用,此选择下系统层面的网络连接无法通过代理服务器进行连接。
<img src="https://ooo.0o0.ooo/2016/10/22/580b74aea7694.png" alt="05.png"></p>
<h2 id="连接代理">连接代理</h2>
<p>返回程序<strong>首页</strong>点击小飞机标志连接代理。
<img src="https://ooo.0o0.ooo/2016/10/22/580b74ae8e310.png" alt="06.png"></p>
《日本的思想》读书笔记
https://acuario.xyz/others/japanese-thought-clip/
2023-09-27T18:25:39+00:00
2016-10-09T22:54:10+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>第64页</p>
<p>我们的传统宗教,没有一个能发挥与新时代流入的意识形态进行思想交锋、并通过这个交锋使传统发挥自觉再生的作用,因此新思想一个一个地被无秩序地积埋,使近代日本人精神上的杂居性愈演愈烈。日本的近代天皇制正试图把权力核心同时作为精神“机轴”用以对付这种事态,但是,因国体是以杂居性的“传统”本身作为自身的实体的,所以它并不能成为将我们的思想进行实质性整合的原理,而只在否定性的同质化(异端的排除)作用方面发挥了强大作用,它对于人格性主体——无论是自由认识主体上的意义、伦理责任主体的意义或是秩序形成的主体的意义——的确立,从一开始就包含着成为决定性桎梏的命运。战后的变革使得这个似是而非的“精神机轴”一举颠覆。在这里,原本存在于日本人精神状况中的杂居的无秩序性,由于第二次“开国”几乎显露到了极限。思想界的纷乱这个词在明治以来,曾是统治阶层以及道学保守主义者的共通说法。但是,思想与现实之间自由地相互交流的条件,在战前明显地受到了阻碍,就此看来,可以说,现在我们才开始迎来了真正的思想的纷乱。实在不知从中会产生出什么,但是可以确切地说,是我们已经不能从这个地点折回,也没有必要从这个地点折回了。</p>……
<p>第64页</p>
<p>我们的传统宗教,没有一个能发挥与新时代流入的意识形态进行思想交锋、并通过这个交锋使传统发挥自觉再生的作用,因此新思想一个一个地被无秩序地积埋,使近代日本人精神上的杂居性愈演愈烈。日本的近代天皇制正试图把权力核心同时作为精神“机轴”用以对付这种事态,但是,因国体是以杂居性的“传统”本身作为自身的实体的,所以它并不能成为将我们的思想进行实质性整合的原理,而只在否定性的同质化(异端的排除)作用方面发挥了强大作用,它对于人格性主体——无论是自由认识主体上的意义、伦理责任主体的意义或是秩序形成的主体的意义——的确立,从一开始就包含着成为决定性桎梏的命运。战后的变革使得这个似是而非的“精神机轴”一举颠覆。在这里,原本存在于日本人精神状况中的杂居的无秩序性,由于第二次“开国”几乎显露到了极限。思想界的纷乱这个词在明治以来,曾是统治阶层以及道学保守主义者的共通说法。但是,思想与现实之间自由地相互交流的条件,在战前明显地受到了阻碍,就此看来,可以说,现在我们才开始迎来了真正的思想的纷乱。实在不知从中会产生出什么,但是可以确切地说,是我们已经不能从这个地点折回,也没有必要从这个地点折回了。</p>
<p>第58页</p>
<p><strong>理论信仰的产生</strong></p>
<p>然而马克思主义在日本具有如此巨大的思想史意义,其本身还有着悲剧与不幸的缘由。近世合理主义的逻辑与基督教的良心以及近代科学的试验操作精神——这三者作为现代西欧思想的传统,或明或暗地成为马克思主义的前提。而究竟由怎样的世界观来把这三者的任务兼于一身付诸实现呢?日本的马克思主义难堪如此重负,这也不足为怪。反过来说,首先第一点,凡理论性的东西、概念性的东西、抽象性的东西,都遭到了日本式感性的抵抗和排斥,结果,马克思主义必须完全承受这一切。第二,不仅马克思主义者,一般的哲学家、社会科学家、思想家也在这一点上多少有些相通,尤其是专家以外的广大读者层或是政治家、实业家、军人、新闻工作者等等,在把哲学、社会科学作为一种“教养”来重视时,则以更激烈的形式表现出对理论乃至思想的拜物教倾向,正是因马克思主义具有体系性,以致使人们认为似乎这是马克思主义特有的。也正如马克思主义独占了“思想问题”一样,直到今日,人们仍认为公式主义是马克思主义的专卖。这时“公式”所包含的意味和机能几乎没有得到反省。而且,马克思主义以外的主义、世界观、教义等等在日本的土壤中被理解和信奉时,难道没有形成不亚于马克思主义的公式主义吗?此类问题亦往往被人们忽略。</p>
<p>理论信仰的发生与制度的拜物化在精神构造上是对应的。近代日本在引进制度或“机制”时,并不是将其作为创造源泉的精神——自由的主体站在严密的方法自觉的立场上,将对象进行概念性整合,通过不断的验证将其再构筑的这种精神——而是作为既成品来接受的,与此相平行,在此往往不是重视其从现实出发的抽象化作用,而是重视其被抽象化了的结果。因此,理论、概念等就失去了作为虚构的意味,反而转化成了一种现实。因此,外国的教员们常带着讽刺的意味发出惊叹,说日本的大学生、知识分子通过各种各样范畴的“抽象的”组合进行概念操作,比起西方人来还得心应手。</p>
<p>然而这样一来,被置于与现实同一平面的理论,与丰饶的现实相比,当然就显得贫乏而可怜。特别是对于前面所述的那种与“实感”紧密结合的文学家来说,这种理论几乎是难以忍受的精神上的暴力。由于公式成为了公式主义,所以对其的抗拒也就成了对公式本身的蔑视,以致实感信仰与理论信仰形成了种无尽的恶性循环。</p>
<p>另外,第三,在理论与现实的关系上,作为总体世界观的马克思主义,其特有的思考方式与日本的知识分子的思考方式相结合,进一步加速了理论的拜物化倾向,这一点也是不能忽视的。众所周知,黑格尔主义主张密涅瓦的猫头鹰①到了傍晚才起飞,即当一定的历史现实几乎毫无保留地得到展现之时,哲学将理性地把握之,并使之上升到概念的层次。马克思主义是在继承这一立场的同时并将其逆转的过程中成立的。世界的总体性自我认识的成立正好成了世界没落的印证,这正是马克思试图将资本制生产全过程理论化的超乎寻常的能量源泉之所在。然而,对历史中的现实进行总体性把握的这种想法,一旦扎根于日本这个传统上还缺乏把理论作为虚构来思考的国家,往往会导致轻易地信仰理论(乃至法则)与现实之间会形成某种预定调和的倾向。</p>
<p>①密涅瓦(Minerva)的猫头鹰:密涅瓦是罗马神话中掌管技术的女神,密涅瓦的猫头鹰被认为是智慧的象征。</p>
<p>第56页</p>
<p><strong>日本的马克思主义在思想史上的意义</strong></p>
<p>在所有的政治和社会的意识形态中嗅出一种“不洁的抽象”一味地沉溺于自我的实感,这种思考方式一旦压倒地被巨大的政治性现实例如战争所围绕,几乎都用与对自然的现实同样“纯粹”的心情将其绝对化,关于这个过程,在此不作深入叙述。不过,最后,我想把代表我国社会科学的思考、并传统触发了文学“实感”的抵抗的马克思主义的问题,与上述题目联系起来,对近代日本的知性构造中的问题性作—个概括。</p>
<p>马克思主义一手独揽了代表社会科学的地位,这自有与其相应的必然性。第一,有了马克思主义,日本的知识界才因之而开始把社会现实分别地按政治、法律、哲学、经济等方面来把握,不仅如此,并且学会了用相互联系的观点来综合地考察问题的方法。另外关于历史,也学到了不单单用历史资料确定个别事实,或只着眼于领袖人物的枯荣兴衰,而是寻求在多样的历史表象背后驱动历史运动的基本导因。这种综合社会科学和构造性历史学的观点,虽然在移植孔德、卢梭、斯宾塞、巴克尔等人思想的明治初期出现过。但由于天皇制的统合过程以及如同在欧洲十九世纪以后社会科学的个别化专门化急速推进,一方面学术机构的各科起初就以专门化学问的形态引进,另一方面新闻传媒则越来越大众化,这两方面的原因使上述观点从知性世界中便不知不觉地消失了。马克思主义的一个巨大的学问的魅力就在于此。</p>
<p>第二,与上述的内容相关联,马克思主义明确揭示出,任何科学研究都不可能完全没有前提,不管自己是否意识到,科学者都是站在一定的价值取向上进行理性操作的。以往只是在哲学方面、而且是极其观念地意识到了的学问与思想不可割离的关系,马克思主义则以“党派性”的过激形态,将其推到了所有科学者面前。而且,这种思想不是用来对世界作各种解释,而是把改变世界作为自己的必然任务的。认识的主体一旦从作为直接所与的现实中隔离开来,置身于与之甚为紧张的关系中,从而逻辑性地重新构成世界,这样才能使理论成为推动现实的杠杆。这种自笛卡儿、培根以来,当然地内在于近代知性中的逻辑,在我国可以说是因马克思主义才得以大规模地唤醒。另外,在我国这个向来没有基督教传统的国家,也正是马克思主义以广泛的社会规模教会了我们:“思想”不单是书斋里精神享受的对象,思想肩负着作为人的人格责任。即便共产党人的大量转向,如前所述,其思考方式大多数是以传统的形式出现的,但思想的转向好歹也以各种形式留下了一种良心上的印记,这至少在以往的“思想”中是看不到的。仅由此点也可以明白把马克思主义给日本知识分子带来的深刻影响与对待其它的外来思想那样,一概归结为日本人的追逐时尚和知性好奇心,这是多么肤浅的观点!</p>
<p>第55页</p>
<p><strong>实感信仰的问题</strong></p>
<p>日本的近代文学,是被“家”的同化和“官僚的机构化”这两股推进日本的“近代”的强大的力量挟持着,在力图抓住自我的现实感的努力摸索中起步的。并且,在这里,(i)在表现感觉的细微差异上词汇丰富,而在表现逻辑性的、普遍性的概念上词汇贫乏的日语特性,(ii)与以上的日语特性相关联,将感情寄托于四季自然,或者对人的言行举止进行细致观察,并且将微妙摇摆的“心情”用极度精练的文体来形象化的日本文学的传统,(iii)现实主义只作为劝善惩恶的反命题而产生,不具备合理精神(古典主义)和自然科学精神作前提,因而容易与国学的那种把事实绝对化和紧密贴合于直接感觉的传统相连接,以致在自我意识内部,规范感觉极难从欲望和好恶感情中分离开来,(iv)大多数文学者(不包括鸥外那样的例子)或是从官僚制的阶梯中落伍者,或是对直接环境(家和乡土)的逃逸者,要不然就是为了弥补政治运动的挫折感才进入文学领域的,不管哪种情况,都背离了日本帝国“正常”的臣民途径,作为“多余者”已为自己和他人所认可的。由于这些情况,这些文学者与制度上的近代化的关系变得淡薄,从而超越自觉的思想立场,不得不显著地倾向于“传统的”心情和美感方面。</p>
<p>对制度的反抗(反官僚的情绪)与对抽象性、概念性的生理上的厌恶难以分离地结合在一起,加之胚胎于对如前所述“升官发迹社会”的地位名誉的反感和轻蔑(有时是自卑感)的反俗物主义,借助了佛教式的某种厌世观,便产生出俗世=现象的世界=概念的世界=规范(法则)的世界这样一个等式,对合理性思考、法则性思考的反抗便越发“传统化”了。而且,也不具有像欧洲的浪漫主义者那种从根本上否定自然科学知性的精神,因为整个近代日本,对自然科学及技术成果过分依存,日本文学者也缺乏对科学真确性存疑的强烈或者说是顽固)态度。这样一方面是不可否定的自然科学领域,另一方面是感觉所能触及的狭隘的日常现实,唯有这两极被作为确实的世界而保留了下来。文学上的实感,也只在后者狭隘的日常感觉世界中,或在由绝对自我超越时空,并以“自由”的直观来把握瞬间闪烁的真实之中得到满足。而介于两者之间的“社会”这一世界则本来就是暧昧的,不论从哪个角度都可以解释的,最终都不外是逐渐变化而过的现象。究极的选择只归于 2×2=4,或文体的问题!(小林秀雄《致X的信》)</p>
<p>第46页</p>
<p>日本统一国家的形成和资本的原始积累的强势实施,在迅速应对国际压力、从而“不亚于外国”的目标下以惊人的速度推进。不用说,这些已经原原本本地被一刻也不停息的近代化官僚制的统治贯彻到末端的行政村,以轻工业以及巨大军需工业为主轴的产业革命被迅速推行所继承。之所以如此其社会的秘密之一,在于以自主性特权为依据的封建的、身份上的中间势力的抵抗力非常脆弱。在明治政府开设帝国议会之前不得不先创设华族制度(造出来的贵族制,这本来就是形容矛盾)由此讽刺意味可知,像欧洲的那种承担社会荣誉的坚韧的贵族传统自治都市、特权行会、拥有禁入权的寺院等对国家权力形成社会性抵抗的势力,在日本是何等的脆弱。前面论述过的“出人头地”的社会流动性之所以能相当早期地形成,其原因就在于此。在政治经济文化及所有方面,近代日本都是暴发户型进升的社会(统治层本身则多由这些暴发户构成)而未经民主化的“大众化”现象也伴随着科技的普及而比较早地就显著形成了。</p>
<p>第45页</p>
<p>经历了从霍布斯到洛克再到卢梭而完成的近代国家政治理论,与近世认识论的发展并行,虽然各有很大的不同,但都同样地承继了由主体的作为使经验世界组组织化的这种想法,把作为顶端的创造主体的君主的作用转回到底层的主体的市民的作用上。而且,此时作为虚构的国家观还结出了社会契约论的果实,而对于“生的充溢”与制度之间的距离感依然被保持着。使这两者的二元紧张关系得以逻辑化的,正是确立“自然状态”和国家状态——仍以各自不同的方法——的关系。即使“契约说”作为一种“学说”变得陈腐以后,那种把“由绝大多数人服从于少数人”的旧有政治社会的现实看成“一个惊人的现象”的自觉意识(H. J. Laski, The Grammar of Politics, p. 21),在上述紧张意识的支撑下形成了市民社会的传统,并成为不断地对权力正当性的根据进行质疑的源泉。</p>
<p>第39页</p>
<p>同样是儒教的自然法思想,在中国则表现出较强的规范性、契约性的特征,而在日本却表现出权威(恩情)和报恩的契机,这并不仅是学者解释上的差异,而是渗透到封建制或家产官僚制内部构成其现实的作用关联的一种“精神”。</p>
<p>第35页</p>
<p>由于战败而接受了波茨坦宣言,因此日本统治层要再一次、这回则是在极其绝望的状况下,被迫给国体下―个极限的定义。我方(日本)在接受波茨坦宣言时,附加了“在允许了不包括要求变更天皇对国家的统治大权的情况下”这一条件,对此,盟军方面的回答是,“天皇及日本政府对国家统治的权限”“从属于盟军最高司令官”,日本的最终统治形式将根据“国民自由表明的意思”来决定。“subject to”在此“勉强意译为‘在限制之下’”,“The ultimate form of ( the ) govemment of Japan”“译为‘最终的日本国政府的形态’,以此尽量避免使用可能联想到包含天皇的国体之类的政治形态或统治组织等用语”(外务省编《终战史录》,第 631 页,原文有着重号)。尽管外务当局如此煞苦心,但在御前会议中,这种写法是否意味着国体的变革这―问题仍引起了十分激烈的争论,以致推迟了投降的决定,这是众所周知的了。令人吃惊的,与其说是在此最后关头日本统治层依然最关心维护国体,毋宁说是对于统治阶层如此具有决定性意义、并在事实上作为国民统合“原理”起着如此有效作用的这个实体终究意味着什么?关于这―点,在日本帝国的最高首脑层次也得不出―致的结论,最后只能由“圣断”来解决。而且,围绕着“圣断”是否能保全国体这―问题,军部又分裂为“承诏必谨派"和“神州防卫派”!后者认为“即便―时违背天皇裕仁的意图,但能守住皇祖皇宗以来建立的国体的本旨,那么在更大的意义上是真正的忠节气(大井笃《天皇制与太平洋战争》,同前,第 752 页)。</p>
<p>第33页</p>
<p>曾在东京大学执教的莱德雷在所著的《日本=欧洲》(Japan-Europa,1929)一书中记录了他在日本期间所见识而感到震动的两件事。一件是大正十二年末发生的难波大助的摄政宫狙击事件(虎之门事件)。此事件之所以令他震惊,与其说是狂热主义者的行为本身,不如说是“接下来发生的事”。内阁辞职,从警视总监到路边值勤的警察等一连串的“责任者”(作者强调他们都不在能阻止凶犯恶行的位置)都受到了免去官职的惩罚,不仅如此,而且连犯人的父亲也被辞去众议院议员之职,在门前围起竹栅栏,足不出户;乡里的人们也取消了正月的庆祝进入“丧”期;连大助曾毕业的小学的校长乃至班级训导都因曾经教过如此不法之徒而辞职。这样一种对责任的漫无边际的承担方式,还有把这看成理所当然的社会的无形压力,在这位德国教授眼里完全是一幅异样的光景。他所举出的另一件事,即(大概是在大地震时)为了抢救出在大火中燃烧的天皇照片,很多学校的校长都因此殒命。“进步团体曾提议,应该让此等怕遭不测的天皇照片远离学校。与其让校长们烧死,还不如把照片烧掉,这种想法居然完全没有成为问题。"(着重号是莱德雷的强调,原书230页)日本天皇制也许的确不像沙皇主义在权力行使方面那样残忍,但是,西欧的君主制,甚至与东正教会相结合的帝政俄国,也难以想像出这种对社会责任的承担方式。这里并不是要讨论孰好孰坏,应该指出,这里潜在的问题,与代日本的“精神”和“机构”都绝非无缘,也非例外。</p>
<p>第28页</p>
<p>“仅仅大不能算是伟大,极尽奢侈也不能算是高尚。加入到所谓现代文明大机构组织中的个人,正成为机械习惯的奴隶,受到曾由自己制造的怪物无情地制御。虽然西方高谈自由,但为了争得财富而伤害了真正的个性,为了无穷无尽的渴望而牺牲了自己的幸福和满足。西洋夸耀自己从中世的迷信中得到解放,又是如何看待对富有的偶像崇拜的呢?在现代绚烂的假面背后,又隐藏着多少苦恼和不满呢?”(《日本的觉醒》岩波文库版,54页)冈仓天心的这段话是很有“预言性”的,如果隐去其名,便可与奥尔特加、瓦勒里、汤因比等思想家的“精神危机”的名言完全相通。</p>
<p>然而并不像人们单纯的理解那样,从文明开化到自由民权的一系列思想,——与后来的国粹主义抬头的时代相比——它们对欧洲的理解并不是那么“天真的”。一直就有人指出,以天赋人权论为依据的民权论者中,大部分人存在着如下思想的分裂,即在国内采取自然法合理主义立场,在国际社会则采取弱肉强食观念的。(参照:冈义武《明治初期自由民权论者眼中的当时国际形势》,《明治史研究丛书》第四卷所收。)罗素曾经辛辣地指出,欧洲文化相对于中国文化的优越性,并不是基于但丁、莎士比亚、歌德比孔子、老子占优势,而是基于这样一个更残酷的事实,即平均起来一个欧洲人杀死一个中国人要比相反的情况更容易一些。而对于东洋来说,最切身而具体的感受是,“欧洲近代”意味着与帝国主义相结合的机械和技术。但从我国来看,先是对中国的思想文化传统抱有“传统的”自卑感,继而又对西洋抱有自卑感,因此,东洋与西洋的问题,和日本作为东洋“近代化”优胜者的问题在思想上交错,这种交错后来甚至强化了日本实现帝国主义的发展的虚伪意识的性格,促成了轻率的东西方“综合”观的发酵。</p>
<p>第26页</p>
<p>而且直到今天,战争期间的那些著名“世界史的哲学”家还在说“日本新宪法是建立在轻视国家、社会义务,极度重视个人人权的权利一边倒的基调上的,这宛然是社会思想产生之前的时代产物,提倡的是法国大革命人权宣言时代的主张。提出新类型的权利,还不能保证新宪法的新时代性和进步性。在经过了为社会公共福利而抑制自由主义的偏重个人权利、尊重义务的社会主义精神阶段之后的现阶段,如何调节权利义务的关系,这应成为有最先进思想立场的课题。从这一点来看,我们可以说日本的新宪法在其思想基调上,是存在于社会主义以前阶段的时代错误的作品”(高山岩男《战后日本的精神状况》127―128页,《现代宗教讲座》VI),他们如此指责,并嘲笑那些“叫嚣拥护这个旧时代的宪法”的知识分子和社会主义政党的“时代错误”。在这里,加藤弘之以来的那种极陈腐的批判方式在与庸俗的发展阶段论相结合中重新表现出来了。</p>
<p>第21页</p>
<p>“神道”可以说像一个毫无内容而不断延长的空白布筒,它是用每个时代强有力的宗教“习合”(指把相异的教理折衷调和—译者)来填充其教义内容的。毋庸置疑,神道的这种“无限拥抱”性和思想杂居性,集中地表现了上述指出的日本思想的“传统”。正因为它没有绝对者,又没有以独特的方式形成对世界进行逻辑性、规范性整合的“道”,所以对外来意识形态的感染也无抵御的装备。国学试图对“布筒”中的内容进行清扫——排除汉意和佛意——时,自然要面对这样一种矛盾,即两个难以区分的契机中,赞扬前者(即没有“道”)却又慨叹者(即思想的感染性)。(这也是后来所有国粹主义者所面临的矛盾。)宣长这种完全靠着直接感觉,拒绝一切抽象化的方法,在社会和政治方面反而导致了这样的机会主义,不以儒治则难治时,就以儒治国。无佛则不能成就时,则以佛治国,此皆其时之神道也”(《铃屋答问录》)。与此相对照,试图重新构筑“神道”世界观的笃胤,则作为“道”的规范化所要付出的代价,去再次“拥抱”儒佛甚至包括基督教,表现出一种泛日本主义。</p>
<p>第20页</p>
<p>不过,这里特别显著的一点是,宣长把道、自然、性等范畴的一切抽象化、规范化都当作汉意一律加以排斥,并把一切抽象的议论全部排斥,只想追求纯感觉上的事实。由此,他的批判即便能算是意识形态揭露,但本来就不可能是以一定的原理立场作根据的意识形态批判。这虽然准确地触及了儒者对其教义的现实妥当性缺乏斟酌的盲点,但由此而摈弃一切逻辑化即抽象化,认为日本不存在规范化思考,这恰恰证明了日本事实上的良好状态并不需要任何“教义”,从而否定了现实与规范之间紧张关系本身的意义。由此而产生的倾向,一方面是对与生俱来的感性的尊重,另一方面则是对既成的统治体制的被动追随,结果只能是在这两重意义上对“既成的”状况作出肯定现状的反应。</p>
<p>第19页</p>
<p>所谓富强者,既非我有,而适足以借贼兵赍盗粮耳。”(同上、卷一)强调了思想国防的重要性。这里我们可以发现杜勒斯式的间接侵略的逻辑已经完全成型并显现出来。当然,人们也许会说这只是在突然面对异文化激烈冲击时,传统集团一同显示出来的一种自卑感。要是如此,那么本居宣长著名的儒教批判方式又如何解释呢?他指出:“在汉土,所谓道究其要旨无非二法也,即夺人国与防人夺己国而己。”因此,比如“所谓天命,在彼国古代不过是灭君夺国的圣人为开脱罪责而捏造出来的口实罢了”(《直昆灵》)。这里与其说是以哲学构筑为荣的儒教思想的冗长理论一“设置了各式各样的繁杂名目”—的内容本身为问题,不如说揭露了它是一种替统治者或篡权者隐瞒或美化现实的意识形态。</p>
<p>第19页</p>
<p>对意识形态的批判在欧洲成为一般常识,是到了第一次世界大战后,那一代人“不仅目睹了对各种观念的真理性的普遍不信,并目睹了对各种观念的主张者的动机的普遍不信”(K. Mannheim,Ideology and Utopia,Preface by L. Wirth,XIII)以后才发生。</p>
<p>第16页</p>
<p>在此并不是说上述这些东西之间是没有任何类似性的,也不是说找出其中的共通性本身没有意义。如果说人类的思考自古以来不会发生什么变化,那讨论便到此止了。应指出,在理解异文化背景下的精神作品时,我们非常缺乏首先把它看成与自己彻底不同的东西来对待的心理准备,从在这种意义上表现出的良好的事物理解力所产生的与异文化轻易接合的“传统”,反而阻碍着任何外来文化形成传统,这才是重要的问题点。特别是明治以后,在对知识贪婪的好奇心和头脑置换转移的迅速性——这的确可算世界第一流,这正是日本飞速“跃进”的一个关键因素——由于吸收外国文化的“传统”,在现代的知识阶层里,就其思想而言,似乎对“未知事物”的感觉已经完全丧失。最初表现出来的是好奇心,但马上就会说“哦,不外是那个”,过敏症与感觉迟钝症如此违背逻辑地结合在一起。比如,在西欧或美国等的知识界中,关于民主主义的基本理念、民主主义的基础这种已有数百年历史的题目,依然被反复质疑,从正面进行探讨。但在日本,战后仅过数年,就轻率敷衍地说“民主主义”“已经都弄明白了”。上述两种状况所形成的巨大反差实在令人惊叹。</p>
<p>第14页</p>
<p>新事物的迅速胜利和旧事物稀里糊涂的潜入、沉积,本来就构成同一精神“传统”的两个方面,而这两个方面又不仅仅以上述方式表现出来。欧洲的哲学、思想本来所具有的历史构造性屡次被分解,或被割断了其思想史的前提,仅作为零件不断地吸收进来。其结果,那种经过高度抽象的理论却意外地在扎根于我们旧习惯的生活感情中受到欢迎,在欧洲本来是对根深蒂固的传统进行殊死抵抗的东西,在日本反倒与“常识”性的想法轻而易举地相一致,或是最新的舶来品与原有的手头上的思想库存顺利地吻合,这样的情况屡见不鲜。</p>
<p>第9页</p>
<p>现在想提起注意的是,传统思想在维新后越发增强了零碎片断的性质,既不能将各种新思想从内部进行重新构建,亦不能作为与异质思想断然对抗的原理发挥作用。正因为如此,尽管各个思想内容及其所占地位有着巨大差异,但在思想摄取与表面交锋的方法上,“前近代”与“近代”反而产生出相互连续的结果。</p>
<p>第8页</p>
<p>如果把我们的思维方式分解成一个个要素,再分别追溯这些要素的谱系的话,就会发现有佛教的因素、儒教的因素、萨满教的因素、西欧的因素——总之,最终是在我们的历史上印下足迹的所有思想的断片。问题在于这些因素皆杂乱地聚在一起,其相互之间的理论关系和该占的位置全然不明确。从这种基本的存在方式来看,无论是所谓的“传统”思想还是明治以后引进的欧洲思想,都看不出其本质上有何区别。人们反复地慨叹近代日本舍弃了维新以前的思想遗产而“欧化”了(而且这种慨叹从明治以后至今日已经成为定式),但是假如具有数百年背景的“传统”思想能真的作为遗产形成了传统,那又怎么会那样轻易地被“欧化”的怒涛所吞没呢?</p>
<p>第7页</p>
<p>儒教、佛教以及与之相“习合”而发展的神道,或江户时代的国学等,常常被统称为传统思想,以此与明治以后大量流入的欧洲思想相对比。区别这两种类型本身并没有错,而且也是有意义的。但是,以传统与非传统的范畴来区分两者,有可能会导致重大的误解。因为外来思想被摄取进来后,便以各种形式融入我们的生活方式和意识中,作为文化它已留下难以消除的烙印。从这种意义上说,欧洲的思想也已在日本“传统化”了。即使是翻译思想,甚至是误译思想,也相应地形成了我们思考的框架。</p>
<p>第5页</p>
<p>思想没能在对抗和积累的基础上历史地形成构造,这一“传统”表现得最明显而又滑稽的例子,便是日本的论争史。某一时代所进行的激烈论争,极少能成为共有财产而为下一时代所继承发展。不管是自由论、还是关于文学的艺术性与政治性的论争,以及知识分子论、历史的本质论等等,同样的问题提法,在不同的时代反复成为论坛的讨论题目。当然,思想的论争本来就没有绝对的结论可言,但在日本,大多数的论争往往没有就某些问题进行分析和整理,也没有明确归结出遗留的问题就不了了之。过了很久以后,因某种契机又对实质相同的题目展开论争,这时也并不是从前次论争所到达的结果出发,而是每回都一切从零开始讨论。还有,比如那些多少与文化或世界观的本质相关的题目,尽管这些题目具有高度的普遍性,但其在欧洲所经历的长年深入探讨的思想背景却往往在日本的论争中被完全置之度外——尽管产生于欧洲的作品已不断流入了日本——因此从“思维的经济性”的角度来看,这也是巨大的浪费。在这里,(1)一方面,日本“学界”整天忙于经销输入的“完成品”,另一方面社会又产生了一种逆反现象,就是“独创性”崇拜,即把零碎片断的偶然想法当作“独创”来极度尊崇,这种崇拜在评论界和大众传媒的推动下得以不断地再生产。而且两者之间互相轻蔑的恶性循环(这一点和后述部分有关联)也在其中起作用。(2)因为各时代各集团与当时西方占有力地位的国家或思潮分别形成横向联系,造成了一个封闭的欧洲形象,所以纵向的历史性思想关联被无视了。(3)不言而喻,现代常见的最单纯的原因,就是论争被搬上大众传媒时,便按着传媒所布设的轨道发展,从而愈益背离论争者当初的意图。但是,像明治二十年代有名的基督教与国体的关系论争,在佛教徒与儒教思想家责难基督教徒的根据里,几乎看不到幕末时的、更何况是十六世纪基督教传来时的责难根据得到了发展的痕迹。这样看来,不得不说问题是波及到日本思想史的一般形态。因为不言而喻,“论争”是辩证法的原始形态。</p>
<p>第4页</p>
<p>若表达得露骨一些,也就是说,在我国没有形成这样一种思想传统,即那种可以给各个时代的观念和思想赋予相互关联性,使所有的思想立场在与其相关的关系中——即使是通过否定而形成的关系中——力图定立自己的历史地位的那种核心性的、或相当于坐标轴的思想传统。我们不要只悲叹或美化自己所处的位置,而应首先敢于正视这种现实,我们只能够从这一 实出发。</p>
<p>第9页</p>
<p>所谓在可能性中来理解,比如,作为完成了的思想,或作为思想的实践上的结果,从“反动”的东西里可以找出“革命的”契机、服从的说教中也可以找出反逆契机、谛观之中也可以找出能动的契机,或者说就是去发现各自的对立面的思想史的方法。</p>
<hr>
<p>以上摘自:
<img src="https://img1.doubanio.com/lpic/s4438007.jpg" alt="《日本的思想》">
<a href="https://book.douban.com/subject/3662234/">《日本的思想》</a><br>
作者:(日)丸山真男<br>
译者: 区建英 / 刘岳兵<br>
出版社:生活·读书·新知三联书店</p>
<p>相关视频:
<a href="http://v.youku.com/v_show/id_XMTMzMTIzNjI1Ng==.html">梁文道第三十八夜:日本的思想(一)</a>
<a href="http://v.youku.com/v_show/id_XMTMzMjM0MTg2NA==.html">梁文道第三十九夜:日本的思想(二)</a></p>
局域网内Linux挂载Windows共享文件夹
https://acuario.xyz/posts/mount-windir-in-linux-for-LAN/
2023-09-27T18:25:39+00:00
2016-10-05T22:25:40+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>为实现在 Linux 服务器上的开发环境实时映射局域网内 Windows 的共享文件夹进行开发,我们可以使用 Linux 的 mount 功能把局域网内 Windows 的共享文件夹挂载到指定目录。在此将实现步骤罗列,给需要的人以参考。</p>
<h2 id="windows">Windows</h2>
<ol>
<li>添加专用于挂载的 Windows 新用户,设置用户名为 <code><username></code>,密码为 <code><password></code></li>
<li>创建 Windows 共享文件夹 <code><shared_dir></code></li>
<li>共享该文件夹:右键单击文件夹 <code><shared_dir></code> 进入 属性 - 共享 - 高级共享 - 共享此文件夹。</li>
<li>设置共享权限,权限 - 添加,在 选择用户或组 界面的 输入对象名称来选择 输入框内输入用户名 <code><username></code> 确定添加,并将 <code><username></code> 的权限设置为 完全控制。建议删除 Everyone 用户的共享权限。</li>
<li>确定 / 固定 Windows 在局域网中的 IP 地址为 <code><WinIP></code></li>
<li>关闭 Windows 防火墙</li>
</ol>
<h2 id="linux">Linux</h2>
<ol>
<li>创建 Linux 挂载文件夹 <code><mount_dir></code></li>
<li>以 root 权限运行如下命令挂载文件夹</li>
</ol>
<pre tabindex="0"><code>mount -t cifs -o username="<username>",password="<password>" -o uid=<linuxuser> -o gid=<linuxgroup> //<WinIP>/<shared_dir> /<path>/<mount_dir>
</code></pre><p>其中的 <code><linuxuser></code> 和 <code><linuxgroup></code> 为 Linux 中具有开发环境配置权限的用户和其所在用户组。<br>
上述方法将 <code><shared_dir></code> 内的文件挂载到了 <code><mount_dir></code> 中。你也可以根据自己需要对命令进行微调。</p>……
<p>为实现在 Linux 服务器上的开发环境实时映射局域网内 Windows 的共享文件夹进行开发,我们可以使用 Linux 的 mount 功能把局域网内 Windows 的共享文件夹挂载到指定目录。在此将实现步骤罗列,给需要的人以参考。</p>
<h2 id="windows">Windows</h2>
<ol>
<li>添加专用于挂载的 Windows 新用户,设置用户名为 <code><username></code>,密码为 <code><password></code></li>
<li>创建 Windows 共享文件夹 <code><shared_dir></code></li>
<li>共享该文件夹:右键单击文件夹 <code><shared_dir></code> 进入 属性 - 共享 - 高级共享 - 共享此文件夹。</li>
<li>设置共享权限,权限 - 添加,在 选择用户或组 界面的 输入对象名称来选择 输入框内输入用户名 <code><username></code> 确定添加,并将 <code><username></code> 的权限设置为 完全控制。建议删除 Everyone 用户的共享权限。</li>
<li>确定 / 固定 Windows 在局域网中的 IP 地址为 <code><WinIP></code></li>
<li>关闭 Windows 防火墙</li>
</ol>
<h2 id="linux">Linux</h2>
<ol>
<li>创建 Linux 挂载文件夹 <code><mount_dir></code></li>
<li>以 root 权限运行如下命令挂载文件夹</li>
</ol>
<pre tabindex="0"><code>mount -t cifs -o username="<username>",password="<password>" -o uid=<linuxuser> -o gid=<linuxgroup> //<WinIP>/<shared_dir> /<path>/<mount_dir>
</code></pre><p>其中的 <code><linuxuser></code> 和 <code><linuxgroup></code> 为 Linux 中具有开发环境配置权限的用户和其所在用户组。<br>
上述方法将 <code><shared_dir></code> 内的文件挂载到了 <code><mount_dir></code> 中。你也可以根据自己需要对命令进行微调。</p>
<h2 id="排障">排障</h2>
<p>如果运行 <code>mount</code> 执行挂载时提示 Host 宕机:</p>
<pre tabindex="0"><code>$ mount -t cifs -o username="user",password="passwd" -o uid=user -o gid=usergroup //<WinIP>/dir /path/to
Host is down.
</code></pre><p>这种情况有可能时由于两端的 Samba 协议不匹配造成的。要解决这个问题,首先需要确认是否时由前述原因造成的。可以执行如下命令:</p>
<pre tabindex="0"><code>$ smbclient -L <server_ip> -U <username> -d 256
</code></pre><p>在显示的 debug 信息中可以看到错误信息:</p>
<pre tabindex="0"><code>Connection to <WinIP> failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Failed to connect with SMB1 -- no workgroup available
</code></pre><p>这样可以在执行 <code>mount</code> 命令时增加参数 <code>vers=2.0</code> 来指定协议版本,从而解决这个问题:</p>
<pre tabindex="0"><code>$ mount -t cifs -o username="user",password="passwd" -o uid=user -o gid=usergroup -o vers=2.0 //<WinIP>/dir /path/to
</code></pre><p>如果没有任何输出,有可能已经挂载成功。可以执行 <code>mount</code> 命令查看挂载情况:</p>
<pre tabindex="0"><code>$ mount
</code></pre><p>参考链接:
<a href="https://serverfault.com/questions/414074/mount-cifs-host-is-down">Mount CIFS Host is down</a></p>
用JavaScript为URL瘦身
https://acuario.xyz/posts/simplify-URL/
2023-09-27T18:25:39+00:00
2016-09-23T22:23:17+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>由于 SEO 优化或流量统计需要,邮箱订阅或某些网站会对自身 URL 进行处理,在原 URL 后面追加一系列的标签,形如</p>
<pre tabindex="0"><code>https://zhuanlan.zhihu.com/p/22545574?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
</code></pre><p>其原本的 URL 为:</p>
<pre tabindex="0"><code>https://zhuanlan.zhihu.com/p/22545574
</code></pre><p>带有标签后缀的 URL 不够优雅,分享这样的 URL 时会影响观感,需要手动删除无用参数(有点强迫症的感觉)。</p>……
<p>由于 SEO 优化或流量统计需要,邮箱订阅或某些网站会对自身 URL 进行处理,在原 URL 后面追加一系列的标签,形如</p>
<pre tabindex="0"><code>https://zhuanlan.zhihu.com/p/22545574?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
</code></pre><p>其原本的 URL 为:</p>
<pre tabindex="0"><code>https://zhuanlan.zhihu.com/p/22545574
</code></pre><p>带有标签后缀的 URL 不够优雅,分享这样的 URL 时会影响观感,需要手动删除无用参数(有点强迫症的感觉)。</p>
<p>好在 <a href="https://twitter.com/ibingfei">@ibingfei</a> 给我找了一个 <a href="https://gist.github.com/wozozo/1714762/">解决方案</a>,只需将处理 URL 的 JS 脚本存为书签,使用时点击一下该书签即可。下面是经我稍微改动,加入过滤 acm、mtt、cks 三个标签后的 JS 脚本,仅供参考:</p>
<pre tabindex="0"><code>javascript:(function(){
var search, params, i, re;
search = location.search.replace( /^\?/, '' ).split( '&' );
params = [];
if (!search) return;
i = search.length;
while( i-- ){
if( !search[i].match( /^utm_|^hmsr|^acm|^mtt|^cks|^fb_action|^fb_source|^action_object_map|^action_type_map|^action_ref_map/ ) ){
params.push( search[i] );
} else {
re = true;
}
}
if (re) {
history.pushState('','',location.pathname + (( params.length ) ? '?' + params.join( '&' ) : '' ));
}
})();
</code></pre><p>此法的原理是对 URL 中的无用标签进行正则匹配,从而实现过滤。当然你也可以自行添加过滤规则,只需在其中按 !search[i].match( / <code>|^<标签名></code>/ ) 格式添加标签即可。</p>
<p>举个栗子:如测试后发现 <a href="http://yhyy135.github.io?blabla=hahaha">http://yhyy135.github.io?blabla=hahaha</a> 中,删除标签 blabla 后不影响正常访问,则可在上述 JS 脚本的正则规则中添加 <code>|^blabla</code> 即可。整个 URL 减肥过程如此流畅。</p>
RabbitMQ入门指南PHP版(三)
https://acuario.xyz/posts/rabbitmq-guide-3/
2023-09-27T18:25:39+00:00
2016-09-17T19:46:39+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>RabbitMQ 入门指南 PHP 版系列文章:
<a href="https://yhyy135.github.io/rabbitmq-guide-1/">RabbitMQ 入门指南 PHP 版(一)</a>
<a href="https://yhyy135.github.io/rabbitmq-guide-2/">RabbitMQ 入门指南 PHP 版(二)</a></p>
<h2 id="主题交换机-topic-exchange">主题交换机 Topic exchange</h2>
<p>为进行更为复杂和高级的路由操作,可通过使用主题交换机来实现。
主题交换机的路由键必须是一个由 <code>.</code> 分隔开的词语列表。绑定键也必须拥有同样的格式。携带特定路由键的消息将被主题交换机投递给绑定键与之相匹配的队列。</p>……
<p>RabbitMQ 入门指南 PHP 版系列文章:
<a href="https://yhyy135.github.io/rabbitmq-guide-1/">RabbitMQ 入门指南 PHP 版(一)</a>
<a href="https://yhyy135.github.io/rabbitmq-guide-2/">RabbitMQ 入门指南 PHP 版(二)</a></p>
<h2 id="主题交换机-topic-exchange">主题交换机 Topic exchange</h2>
<p>为进行更为复杂和高级的路由操作,可通过使用主题交换机来实现。
主题交换机的路由键必须是一个由 <code>.</code> 分隔开的词语列表。绑定键也必须拥有同样的格式。携带特定路由键的消息将被主题交换机投递给绑定键与之相匹配的队列。</p>
<p>绑定键和路由键有两种应用方式:</p>
<ul>
<li>* 号表示一个单词</li>
<li># 号表示任意数量(零个或多个)单词</li>
</ul>
<p>举个栗子:所有消息均描述动物。消息所携带的路由键由三个被 <code>.</code> 分隔开的单词组成,第一个单词描述动物的敏捷度,第二个单词描述动物颜色,第三个单词描述物种。格式如:<敏捷度>.<颜色>.<物种></p>
<p>给定三个绑定:
Q1 的绑定键为 *.orange.*,该绑定针对的是所有的桔黄色动物的信息。
Q2 的绑定键为 *.*.rabbit 和 lazy.#,该绑定针对的是所有兔子和所有懒惰的动物。</p>
<p><img src="https://www.rabbitmq.com/img/tutorials/python-five.png" alt="主题交换机"></p>
<p>携带有 quick.orange.rabbit 的消息将会被分别投递给这两个队列;
携带着 lazy.orange.elephant 的消息会被分别投递给这两个队列;
携带有 quick.orange.fox 的消息会投递给第一个队列;
携带有 lazy.brown.fox 的消息会投递给第二个队列;
携带有 lazy.pink.rabbit 的消息只会被投递给第二个队列,即使它同时匹配第二个队列的两个绑定。
携带有 quick.brown.fox 的消息不会投递给任意队列。
携带有一个单词或者四个单词如 orange 或 quick.orange.male.rabbit 的消息时,消息将不被投递,且会被丢弃。
携带有 lazy.orange.male.rabbit 的消息会匹配最后一个绑定,并被投递到第二个队列中。
当一个队列的绑定键为 # 时,该队列将忽略消息的路由键,接收所有消息。</p>
<h3 id="运行代码">运行代码</h3>
<p>源代码:
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/emit_log_topic.php">emit_log_topic.php</a><br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/receive_logs_topic.php">receive_logs_topic.php</a></p>
<p>若需接收所有日志:</p>
<pre tabindex="0"><code>$ php receive_logs_topic.php "#"
</code></pre><p>接收来自 <code>kern</code> 设备的日志:</p>
<pre tabindex="0"><code>$ php receive_logs_topic.php "kern.*"
</code></pre><p>只接收严重程度为 <code>critical</code> 的日志:</p>
<pre tabindex="0"><code>$ php receive_logs_topic.php "*.critical"
</code></pre><p>建立多个绑定:</p>
<pre tabindex="0"><code>$ php receive_logs_topic.php "kern.*" "*.critical"
</code></pre><p>发送路由键为 <code>kern.critical</code> 的日志:</p>
<pre tabindex="0"><code>$ php emit_log_topic.php "kern.critical" "A critical kernel error"
</code></pre><h2 id="远程过程调用-remote-procedure-call">远程过程调用 Remote Procedure Call</h2>
<p>若要将一个函数运行在远程终端上并且等待从远程终端获取结果,可通过远程过程调用(Remote Procedure Call, RPC) 实现。</p>
<h3 id="客户端接口">客户端接口</h3>
<p>创建一个简单的客户端类,用以展示 RPC 服务。它通过 “call” 方法发送 RPC 请求,并在收到回应前保持阻塞。</p>
<pre tabindex="0"><code>$fibonacci_rpc = new FibonacciRpcClient();
$response = $fibonacci_rpc->call(30);
echo " [.] Got ", $response, "\n";
</code></pre><h3 id="回调队列">回调队列</h3>
<p>客户端发送请求信息后,服务端将其应用到一个回复信息中。客户端在发送请求时同时发送一个回调队列(callback queue)的地址用以接收回复信息。</p>
<pre tabindex="0"><code>list($queue_name, ,) = $channel->queue_declare("", false, false, true, false);
$msg = new AMQPMessage(
$payload,
array('reply_to' => $queue_name));
$channel->basic_publish($msg, '', 'rpc_queue');
## ... then code to read a response message from the callback_queue ...
</code></pre><h4 id="消息属性">消息属性</h4>
<p>AMQP 协议为消息预定义了 14 个属性。其中常用的有以下几个:</p>
<ul>
<li>delivery_mode(投递模式):标记消息为持久的(值为 2)或暂存的(除了 2 之外的其他任何值)。</li>
<li>content_type(内容类型): 描述编码的 mime-type。</li>
<li>reply_to(回复目标):命名回调队列。</li>
<li>correlation_id(关联标识):关联 RPC 的响应和请求。</li>
</ul>
<h3 id="关联标识-correlation-id">关联标识 Correlation Id</h3>
<p>为使消息投递更高效,可为每个客户端只建立一个独立的回调队列,并用关联标识来辨别该响应所属的请求。如果消息的关联标识为未知,则忽略消息。</p>
<h3 id="运行代码-1">运行代码</h3>
<p><img src="https://www.rabbitmq.com/img/tutorials/python-six.png" alt="远程过程调用"></p>
<p>RPC 的工作原理:</p>
<ul>
<li>客户端启动时创建一个匿名独占回调队列。</li>
<li>客户端发送的消息带有 reply_to 和 correlation_id 属性。</li>
<li>请求将发送到一个 rpc_queue 队列中。</li>
<li>服务器等待接收请求。请求出现时,它将带有执行结果的消息发送给 reply_to 字段指定的队列。</li>
<li>客户端等待回调队列里的结果。消息出现时,它将 correlation_id 属性与请求匹配的消息返回给程序。</li>
</ul>
<p>RPC 的优势:</p>
<ul>
<li>服务器运行过慢时,可运行另外一个服务器端来扩展</li>
<li>客户端的 RPC 请求只发送或接收一条消息。无需 queue_declare 声明队列异步调用。单个请求只需往返一次。</li>
</ul>
<p>构建一个 RPC 系统:包含一个客户端和一个 RPC 服务器,并创建一个模拟 RPC 服务来返回斐波那契数列。</p>
<p><a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/rpc_server.php">rpc_server.php</a><br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/rpc_client.php">rpc_client.php</a></p>
<p>启动服务器端:</p>
<pre tabindex="0"><code>$ php rpc_server.php
[x] Awaiting RPC requests
</code></pre><p>启动客户端,请求一个 fibonacci 队列</p>
<pre tabindex="0"><code>$ php rpc_client.php
[x] Requesting fib(30)
</code></pre><hr>
<p><strong>相关文章</strong>
<a href="https://www.rabbitmq.com/tutorials/tutorial-five-php.html">RabbitMQ - RabbitMQ tutorial - Topics</a>
<a href="https://www.rabbitmq.com/tutorials/tutorial-six-php.html">RabbitMQ - RabbitMQ tutorial - Remote procedure call (RPC)</a>
<a href="http://wiki.jikexueyuan.com/project/rabbitmq/topics.html">RabbitMQ 能为你做些什么? - 为什么需要主题交换机?</a>
<a href="http://wiki.jikexueyuan.com/project/rabbitmq/rpc.html">RabbitMQ 能为你做些什么? - 远程过程调用</a></p>
RabbitMQ入门指南PHP版(二)
https://acuario.xyz/posts/rabbitmq-guide-2/
2023-09-27T18:25:39+00:00
2016-09-16T00:46:39+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>RabbitMQ 入门指南 PHP 版系列文章:
<a href="https://yhyy135.github.io/rabbitmq-guide-1/">RabbitMQ 入门指南 PHP 版(一)</a></p>
<h2 id="发布订阅-publishsubscribe">发布/订阅 Publish/Subscribe</h2>
<p>分发一个消息给多个消费者(consumers)的模式称为「发布 / 订阅」。若要构建一个简单的日志系统用于发送日志消息和获取消息并输出内容,可利用发布 / 订阅模式实现。</p>……
<p>RabbitMQ 入门指南 PHP 版系列文章:
<a href="https://yhyy135.github.io/rabbitmq-guide-1/">RabbitMQ 入门指南 PHP 版(一)</a></p>
<h2 id="发布订阅-publishsubscribe">发布/订阅 Publish/Subscribe</h2>
<p>分发一个消息给多个消费者(consumers)的模式称为「发布 / 订阅」。若要构建一个简单的日志系统用于发送日志消息和获取消息并输出内容,可利用发布 / 订阅模式实现。</p>
<h3 id="交换机-exchanges">交换机 Exchanges</h3>
<p>RabbitMQ 中完整的消息模型:</p>
<ul>
<li>生产者(producer)是发布消息的应用程序。</li>
<li>队列(queue)用于消息存储的缓冲。</li>
<li>消费者(consumer)是接收消息的应用程序。</li>
</ul>
<p>RabbitMQ 消息模型的核心理念是:发布者(producer)不会直接发送任何消息给队列,其只需要把消息发送给一个交换机(exchange)代为处理。消息处理规则通过交换机类型(exchange type)来定义。</p>
<p>交换机类型:</p>
<ul>
<li>直连交换机(direct)</li>
<li>主题交换机(topic)</li>
<li>头交换机(headers)</li>
<li>扇型交换机(fanout)</li>
</ul>
<p><img src="https://www.rabbitmq.com/img/tutorials/exchanges.png" alt="交换机"></p>
<p>先创建一个名为 logs 的扇型交换机,它将把消息发送给它所知道的所有队列:</p>
<pre tabindex="0"><code>$channel->exchange_declare('logs', 'fanout', false, false, false);
$channel->basic_publish($msg, 'logs');
</code></pre><p>其中 basic_publish() 的第一个变量为发送消息的目标队列。<br>
其中 basic_publish() 的第二个变量为交换机设置 routing_key。</p>
<h4 id="交换机列表">交换机列表</h4>
<p>使用 rabbitmqctl 命令可列出服务器上所有的交换机:</p>
<pre tabindex="0"><code>$ sudo rabbitmqctl list_exchanges
Listing exchanges ...
direct
amq.direct direct
amq.fanout fanout
amq.headers headers
amq.match headers
amq.rabbitmq.log topic
amq.rabbitmq.trace topic
amq.topic topic
logs fanout
...done.
</code></pre><p>其中名为 amq.* 的交换机是 RabbitMQ 默认创建的。</p>
<h4 id="匿名的交换机">匿名的交换机</h4>
<p>在介绍发送消息 Sending 时举例的 <a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/send.php">send.php</a> 中有如下代码:</p>
<pre tabindex="0"><code>$channel->basic_publish($msg, '', 'hello');
</code></pre><p>在该例中我们使用空字符串 '' 设置使用默认交换机。</p>
<h3 id="临时队列-temporary-queues">临时队列 Temporary queues</h3>
<p>调用 queue_declare 方法时,函数参数 queue 的值为空可使 RabbitMQ 创建一个随机命名的队列:</p>
<pre tabindex="0"><code>list($queue_name, ,) = $channel->queue_declare("");
</code></pre><p>若要使其与消费者(consumer)断开连接时被立即删除,可声明该队列为 exclusive。</p>
<h3 id="绑定-bindings">绑定 Bindings</h3>
<p><img src="https://ooo.0o0.ooo/2016/10/29/58142048a263f.png" alt="绑定"></p>
<p>交换机和队列之间的联系我们称之为绑定(binding),绑定时可添加 routing_key 参数。为避免与 basic_publish 的 routing_key 参数混淆,将此处的 routing_key 称为绑定键(binding key)。绑定键将会影响交换机对消息进行的路由操作。扇型交换机会忽略该值。</p>
<p>不带绑定键的绑定:</p>
<pre tabindex="0"><code>$channel->queue_bind($queue_name, 'logs');
</code></pre><p>带绑定键为 black 的绑定:</p>
<pre tabindex="0"><code>$binding_key = 'black';
$channel->queue_bind($queue_name, $exchange_name, $binding_key);
</code></pre><h4 id="绑定列表">绑定列表</h4>
<p>使用 rabbitmqctl 命令可列出所有现存的绑定。</p>
<pre tabindex="0"><code>$ sudo rabbitmqctl list_bindings
</code></pre><h3 id="运行代码">运行代码</h3>
<p><a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/emit_log.php">emit_log.php</a><br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/receive_logs.php">receive_logs.php</a></p>
<p><img src="https://ooo.0o0.ooo/2016/10/29/5814205ccb445.png" alt=""></p>
<p>由于发布消息要求确定存在的交换机,故在 RabbitMQ 连接成功后声明一个交换机。日志消息发布程序把消息发送给 logs 交换机而不是匿名交换机。若未绑定队列到交换机,消息将丢失。若没有消费者监听,则消息会被忽略。执行下列命令将实现 logs 交换机把数据发送给两个系统命名的队列。</p>
<pre tabindex="0"><code>$ php receive_logs.php > logs_from_rabbit.log //将日志存入文件
$ php receive_logs.php //查看日志
$ php emit_log.php //发送日志
$ sudo rabbitmqctl list_bindings //确认已创建的队列绑定
Listing bindings ...
...
logs amq.gen-TJWkez28YpImbWdRKMa8sg== []
logs amq.gen-x0kymA4yPzAT6BoC/YP+zw== []
...done.
</code></pre><h2 id="路由-routing">路由 Routing</h2>
<h3 id="直连交换机-direct-exchange">直连交换机 Direct exchange</h3>
<p>直连交换机将会对绑定键(binding key)和路由键(routing key)进行精确匹配,从而确定消息该分发到哪个队列。<br>
举个栗子:</p>
<p><img src="https://www.rabbitmq.com/img/tutorials/direct-exchange.png" alt="直连交换机"></p>
<p>上图中直连交换机 X 和 Q1,Q2 两个队列进行了绑定。
第一个队列有一个绑定,绑定键为 orange。<br>
第二个队列有两个绑定,绑定键为 black 和 green。<br>
当路由键为 orange 的消息发布到交换机,会被路由到队列 Q1。<br>
当路由键为 black 者 green 的消息发布到交换机,会路由到 Q2。<br>
其他的所有消息都将会被丢弃。</p>
<h3 id="多重绑定-multiple-bindings">多重绑定 Multiple bindings</h3>
<p><img src="https://www.rabbitmq.com/img/tutorials/direct-exchange-multiple.png" alt="多重绑定"></p>
<p>可使用相同的绑定键绑定多个队列。使用 black 绑定键添加 X 和 Q1、Q2 之间的绑定,则带有 black 路由键的消息会同时发送到 Q1 和 Q2。</p>
<h3 id="情景应用">情景应用</h3>
<p>如需把严重的错误日志信息写入日志文件(存储到磁盘),同时仍把所有日志信息输出到控制台中,可利用路由功能实现:将消息发送到直连交换机,以日志级别作为路由键。日志级别 severity 的值是 info、warning、error。接收日志的脚本可根据日志级别来选择其要处理的日志。</p>
<h4 id="发送日志">发送日志</h4>
<p>创建一个交换机(exchange):</p>
<pre tabindex="0"><code>$channel->exchange_declare('direct_logs', 'direct', false, false, false);
</code></pre><p>发送消息:</p>
<pre tabindex="0"><code>$channel->exchange_declare('direct_logs', 'direct', false, false, false);
$channel->basic_publish($msg, 'direct_logs', $severity);
</code></pre><h4 id="订阅">订阅</h4>
<p>根据严重级别分别创建绑定:</p>
<pre tabindex="0"><code>foreach($severities as $severity) {
$channel->queue_bind($queue_name, 'direct_logs', $severity);
}
</code></pre><h3 id="运行代码-1">运行代码</h3>
<p>源代码:<br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/emit_log_direct.php">emit_log_direct.php</a><br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/receive_logs_direct.php">receive_logs_direct.php</a></p>
<p>若只需保存 warning 和 error 级别的日志到磁盘:</p>
<pre tabindex="0"><code>$ php receive_logs_direct.php warning error > logs_from_rabbit.log
</code></pre><p>在新终端中输出所有日志信息:</p>
<pre tabindex="0"><code>$ php receive_logs_direct.php info warning error
[*] Waiting for logs. To exit press CTRL+C
</code></pre><p>输出 error 级别的日志:</p>
<pre tabindex="0"><code>$ php emit_log_direct.php error "Run. Run. Or it will explode."
[x] Sent 'error':'Run. Run. Or it will explode.'
</code></pre><hr>
<p><strong>相关文章</strong>
<a href="https://www.rabbitmq.com/tutorials/tutorial-three-php.html">RabbitMQ - RabbitMQ tutorial - Publish/Subscribe</a>
<a href="https://www.rabbitmq.com/tutorials/tutorial-four-php.html">RabbitMQ - RabbitMQ tutorial - Routing</a>
<a href="http://wiki.jikexueyuan.com/project/rabbitmq/publish-subscribe.html">RabbitMQ 能为你做些什么? - 发布/订阅</a>
<a href="http://wiki.jikexueyuan.com/project/rabbitmq/routing.html">RabbitMQ 能为你做些什么? - 路由</a></p>
RabbitMQ入门指南PHP版(一)
https://acuario.xyz/posts/rabbitmq-guide-1/
2023-09-27T18:25:39+00:00
2016-09-13T02:37:14+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="介绍">介绍</h2>
<p>RabbitMQ 是一个消息代理。核心原理是接收和发送消息。</p>
<p><img src="https://www.rabbitmq.com/img/tutorials/producer.png" alt="生产者"></p>
<ul>
<li>生产 (Producing) 就是发送消息。发送消息的程序就是一个生产者 (producer)。用 "P" 表示</li>
</ul>
<p><img src="https://ooo.0o0.ooo/2016/10/29/58141fc7910a7.png" alt="队列"></p>
<ul>
<li>队列 (queue) 就是邮箱的名称。消息存储在一个队列(queue)中通过你的应用程序和 RabbitMQ 进行传输</li>
</ul>
<p><img src="https://www.rabbitmq.com/img/tutorials/consumer.png" alt="消费者"></p>
<ul>
<li>消费(Consuming)就是获取消息。等待获取消息的程序就是一个消费者(consumer)。用 "C" 表示</li>
</ul>
<p>RabbitMQ 使用的是 AMQP 协议,对于 PHP 来说你可以选择 <a href="https://github.com/php-amqplib/php-amqplib">php-amqplib</a> 作为 RabbitMQ 的客户端。</p>……
<h2 id="介绍">介绍</h2>
<p>RabbitMQ 是一个消息代理。核心原理是接收和发送消息。</p>
<p><img src="https://www.rabbitmq.com/img/tutorials/producer.png" alt="生产者"></p>
<ul>
<li>生产 (Producing) 就是发送消息。发送消息的程序就是一个生产者 (producer)。用 "P" 表示</li>
</ul>
<p><img src="https://ooo.0o0.ooo/2016/10/29/58141fc7910a7.png" alt="队列"></p>
<ul>
<li>队列 (queue) 就是邮箱的名称。消息存储在一个队列(queue)中通过你的应用程序和 RabbitMQ 进行传输</li>
</ul>
<p><img src="https://www.rabbitmq.com/img/tutorials/consumer.png" alt="消费者"></p>
<ul>
<li>消费(Consuming)就是获取消息。等待获取消息的程序就是一个消费者(consumer)。用 "C" 表示</li>
</ul>
<p>RabbitMQ 使用的是 AMQP 协议,对于 PHP 来说你可以选择 <a href="https://github.com/php-amqplib/php-amqplib">php-amqplib</a> 作为 RabbitMQ 的客户端。</p>
<h2 id="hello-world">Hello World!</h2>
<p><img src="https://www.rabbitmq.com/img/tutorials/python-one.png" alt="Hello World!"></p>
<p>设计一个简单的流程:生产者(producer)把消息发送到一个名为 “hello” 的队列中。消费者(consumer)从这个队列中获取消息。</p>
<h3 id="发送消息-sending">发送消息 Sending</h3>
<p><img src="https://www.rabbitmq.com/img/tutorials/sending.png" alt="发送消息"></p>
<p>发送程序会发送一个消息到队列中。首先要做的事情就是建立一个到 RabbitMQ 服务器的连接。</p>
<p>send.php</p>
<pre tabindex="0"><code><?php
<!-- %1 -->
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
<!-- %2 -->
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);
<!-- %3 -->
$msg = new AMQPMessage('Hello World!');
$channel->basic_publish($msg, '', 'hello');
<!-- %4 -->
echo " [x] Sent 'Hello World!'\n";
<!-- %5 -->
$channel->close();
$connection->close();
?>
</code></pre><ol>
<li>添加必要的库</li>
<li>建立一个到 RabbitMQ 服务器的连接;创建一个名为 hello 的队列,然后把消息发送到这个队列中。</li>
<li>发送的消息存入 $msg;发送的消息存入 $msg;在 RabbitMQ 中,消息是不能直接发送到队列,它需要发送到交换机(exchange)中,将 $msg 通过一个空字符串来标识的交换机投递到 hello 队列中。</li>
<li>提示发送成功信息。</li>
<li>断开连接。</li>
</ol>
<h3 id="获取消息-receiving">获取消息 Receiving</h3>
<p><img src="https://www.rabbitmq.com/img/tutorials/receiving.png" alt="获取消息"></p>
<p>receive.php</p>
<pre tabindex="0"><code><?php
<!-- %1 -->
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
<!-- %2 -->
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);
<!-- %3 -->
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
<!-- %4 -->
$callback = function($msg) {
echo " [x] Received ", $msg->body, "\n";
};
<!-- %5 -->
$channel->basic_consume('hello', '', false, true, false, false, $callback);
<!-- %6 -->
while(count($channel->callbacks)) {
$channel->wait();
}
<!-- %7 -->
$channel->close();
$connection->close();
?>
</code></pre><ol>
<li>添加必要的库</li>
<li>建立一个到 RabbitMQ 服务器的连接;创建一个名为 hello 的队列,然后把消息发送到这个队列中。在 receive.php 中重复声明队列防止程序运行顺序导致的错误。</li>
<li>提示中断程序信息。</li>
<li>为队列定义一个回调(callback)函数,使用回调函数提示发送成功信息。</li>
<li>使用回调函数从名为 hello 的队列中接收消息</li>
<li>输入一个用来等待消息数据并且在需要的时候运行回调函数的无限循环</li>
<li>断开连接。</li>
</ol>
<h3 id="运行代码">运行代码</h3>
<p>源代码:<br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/send.php">send.php</a><br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/receive.php">receive.php</a></p>
<pre tabindex="0"><code>$ php send.php
</code></pre><p>在终端中运行程序发送消息,send 程序在每次运行之后就会停止。</p>
<pre tabindex="0"><code>$ php receive.php
</code></pre><p>在终端中运行程序获取消息,receive 程序并不会退出。它一直在准备获取消息。可通过 Ctrl-C 来中止。</p>
<h2 id="工作队列-work-queues">工作队列 Work Queues</h2>
<p><img src="https://www.rabbitmq.com/img/tutorials/python-two.png" alt="工作队列"></p>
<p>工作队列(又称:任务队列——Task Queues)是为了避免等待一些占用大量资源、时间的操作。当我们把任务(Task)当作消息发送到队列中,一个运行在后台的工作者(worker)进程就会取出任务然后处理。当你运行多个工作者(workers),任务就会在它们之间共享。</p>
<h3 id="准备-preparation">准备 Preparation</h3>
<p>这里使用 sleep() 函数来模拟复杂的任务,在字符串中加上点号(.)来表示任务的复杂程度,一个点(.)将会耗时 1 秒钟。比如 "Hello..." 就会耗时 3 秒钟。</p>
<h3 id="发送消息">发送消息</h3>
<p>按照计划发送任意消息任务到工作队列中</p>
<p>修改 send.php 的第 2,3,4 部分得到 new_task.php,修改 receive.php 的第 2,4,5 部分得到 worker.php,使其按照计划发送任务到我们的工作队列中。</p>
<p>new_task.py</p>
<pre tabindex="0"><code><?php
<!-- %2 -->
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, false, false, false);
<!-- %3 -->
$data = implode(' ', array_slice($argv, 1));
if(empty($data)) $data = "Hello World!";
$msg = new AMQPMessage($data,
array('delivery_mode' => 2)
);
$channel->basic_publish($msg, '', 'task_queue');
<!-- %4 -->
echo " [x] Sent ", $data, "\n";
?>
</code></pre><p>2.建立一个到 RabbitMQ 服务器的连接;创建一个名为 task_queue 的队列,然后把消息发送到这个队列中。<br>
3.发送的单条消息作为发送单元存入 $data,并将其存入 $msg 作为队列发送。<br>
4.提示每一条消息发送成功信息。</p>
<p>worker.php</p>
<pre tabindex="0"><code><?php
<!-- %2 -->
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, true, false, false);
<!-- %4 -->
$callback = function($msg){
echo " [x] Received ", $msg->body, "\n";
sleep(substr_count($msg->body, '.'));
echo " [x] Done", "\n";
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
<!-- %5 -->
$channel->basic_qos(null, 1, null);
$channel->basic_consume('task_queue', '', false, false, false, false, $callback);
?>
</code></pre><p>2.建立一个到 RabbitMQ 服务器的连接;创建一个名为 task_queue 的队列,然后把消息发送到这个队列中。在 worker.php 中重复声明队列防止程序运行顺序导致的错误。<br>
4.为队列定义一个回调(callback)函数,使用回调函数提示发送成功信息。<br>
5.使用回调函数从名为 task_queue 的队列中接收消息。</p>
<h3 id="轮询调度-round-robin-dispatching">轮询调度 Round-robin dispatching</h3>
<p>三个终端,两个用来运行 worker.py 脚本,即两个消费者(consumers)—— C1 和 C2 接收工作者(workers)发送的消息。平均每个消费者都会收到同等数量得消息。这种发送消息得方式叫做——轮询调度</p>
<p>workers:</p>
<pre tabindex="0"><code>$ php new_task.php First message.
$ php new_task.php Second message..
$ php new_task.php Third message...
$ php new_task.php Fourth message....
$ php new_task.php Fifth message.....
</code></pre><p>C1:</p>
<pre tabindex="0"><code> $ php worker.php
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'First message.'
[x] Received 'Third message...'
[x] Received 'Fifth message.....'
</code></pre><p>C2:</p>
<pre tabindex="0"><code> $ php worker.php
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'Second message..'
[x] Received 'Fourth message....'
</code></pre><h3 id="消息确认-message-acknowledgment">消息确认 Message acknowledgment</h3>
<p>如果不对消息进行确认,已发送的消息将马上在内存中被移除。为了防止系统运行导致的任务消息的丢失,我们使用消息确认机制预防此类情况的发生。消费者会通过一个响应(ack),告诉 RabbitMQ 已经收到并处理了某条消息,然后 RabbitMQ 就会释放并删除这条消息。若 RabbitMQ 未收到响应,则会将消息重新发送给其他消费者(consumer)。在进程运行时使用 CTRL+C 终止进程,消息也不会丢失。<br>
消息确认默认关闭。可使用 no_ack=True 标识将其开启:</p>
<pre tabindex="0"><code>$callback = function($msg){
echo " [x] Received ", $msg->body, "\n";
sleep(substr_count($msg->body, '.'));
echo " [x] Done", "\n";
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$channel->basic_consume('task_queue', '', false, false, false, false, $callback);
</code></pre><h4 id="忘记确认">忘记确认</h4>
<p>未声明 basic_ack 标志位将导致无法释放未响应的消息,RabbitMQ 就会占用越来越多的内存。排除该错误可使用 rabbitmqctl 命令输出 messages_unacknowledged 字段:</p>
<pre tabindex="0"><code>$ sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
Listing queues ...
hello 0 0
...done.
</code></pre><h3 id="消息持久化-message-durability">消息持久化 Message durability</h3>
<p>在 RabbitMQ 退出或者崩溃时,将会丢失所有队列和消息。把「队列」和「消息」设为持久化可确保信息不会丢失。<br>
在保证未声明同名的非持久化队列的情况下,在生产者(producer)和消费者(consumer)对应的代码中修改声明 task_queue 队列持久化:</p>
<pre tabindex="0"><code>$channel->queue_declare('hello', false, true, false, false);
</code></pre><p>将 delivery_mode 的属性设为 2,实现消息持久化:</p>
<pre tabindex="0"><code>$msg = new AMQPMessage($data,
array('delivery_mode' => 2)
);
</code></pre><p>PS:RabbitMq 收到消息到保存之间存在一个很小的时间间隔,故消息持久化并不能保证真正的持久化,但已经足够应付我们的简单工作队列。若一定要保证持久化,需改写代码来支持事务(transaction)。</p>
<h3 id="公平调度-fair-dispatch">公平调度 Fair dispatch</h3>
<p><img src="https://www.rabbitmq.com/img/tutorials/prefetch-count.png" alt="公平调度"></p>
<p>RabbitMQ 只管分发进入队列的消息,不会关心有多少消费者(consumer)没有作出响应。它盲目的把第 n-th 条消息发给第 n-th 个消费者。为实现 RabbitMQ 按需处理消息分发,可使用 basic.qos 方法,并设置 prefetch_count=1。这使得 RabbitMQ 同一时刻,不要发送超过 1 条消息给一个工作者(worker),直到它已经处理了上一条消息并且作出了响应。</p>
<pre tabindex="0"><code>channel.basic_qos(prefetch_count=1)
</code></pre><h3 id="运行代码-1">运行代码</h3>
<p>源代码:<br>
<a href="https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/new_task.php">new_task.php</a><br>
<a href="http://github.com/rabbitmq/rabbitmq-tutorials/blob/master/php/worker.php">worker.php</a></p>
<hr>
<p><strong>相关文章</strong>
<a href="https://www.rabbitmq.com/tutorials/tutorial-one-php.html">RabbitMQ - RabbitMQ tutorial - "Hello World!"</a>
<a href="https://www.rabbitmq.com/tutorials/tutorial-two-php.html">RabbitMQ - RabbitMQ tutorial - Work Queues</a>
<a href="http://wiki.jikexueyuan.com/project/rabbitmq/hello-world.html">RabbitMQ 能为你做些什么? - 介绍</a>
<a href="http://wiki.jikexueyuan.com/project/rabbitmq/work-queues.html">RabbitMQ 能为你做些什么? - 工作队列</a></p>
Git 简明教程
https://acuario.xyz/posts/how-to-use-git/
2023-09-27T18:25:39+00:00
2016-08-28T01:10:00+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h2 id="git-简介">Git 简介</h2>
<p>Git 属于分散型版本管理系统,是为版本管理而设计的软件。
Linux 的创始人 Linus Torvalds 在 2005 年开发了 Git 的原型程序。当时,由于在 Linux 内核开发中使用的既有版本管理系统的开发方许可证发生了变更,为了更换新的版本管理系统,Torvalds 开发了 Git。</p>
<h2 id="什么是版本管理">什么是版本管理</h2>
<p>版本管理就是管理更新的历史记录。它为我们提供了一些在软件开发过程中必不可少的功能,例如记录一款软件添加或更改源代码的过程,回滚到特定阶段,恢复误删除的文件等。在 Git 出现以前,人们普遍采用 Subversion 等集中型版本管理系统,而现在 Git 已成为主流。</p>……
<h2 id="git-简介">Git 简介</h2>
<p>Git 属于分散型版本管理系统,是为版本管理而设计的软件。
Linux 的创始人 Linus Torvalds 在 2005 年开发了 Git 的原型程序。当时,由于在 Linux 内核开发中使用的既有版本管理系统的开发方许可证发生了变更,为了更换新的版本管理系统,Torvalds 开发了 Git。</p>
<h2 id="什么是版本管理">什么是版本管理</h2>
<p>版本管理就是管理更新的历史记录。它为我们提供了一些在软件开发过程中必不可少的功能,例如记录一款软件添加或更改源代码的过程,回滚到特定阶段,恢复误删除的文件等。在 Git 出现以前,人们普遍采用 Subversion 等集中型版本管理系统,而现在 Git 已成为主流。</p>
<h2 id="集中型与分散型">集中型与分散型</h2>
<p>以 Subversion 为代表的集中型,会将仓库集中存放在服务器之中,所以只存在一个仓库。这就是为什么这种版本管理系统会被称作集中型。
集中型将所有数据集中存放在服务器当中,有便于管理的有点。但是一旦开发者所处的环境不能连接服务器,就无法获取最新的源代码,开发也就几乎无法进行。服务器宕机时也是同样的道理,而且万一服务器故障导致数据消失,恐怕开发者就再也见不到最新的源代码了。</p>
<p>以 Git 为代表的分散型,例如 GitHub 会将仓库 Fork 给每一个用户。Fork 就是将 GitHub 的某个特定仓库复制到自己的账户下。Fork 出的仓库与原仓库是两个不同的仓库,开发者可以随意编辑。分散型拥有多个仓库,相对而言稍显复杂。不过,由于本地的开发环境中就有仓库,所以开发者不必连接远程仓库就可以进行开发。</p>
<p><img src="https://i.v2ex.co/fAhm82RJ.png" alt="Git 常用命令流程图"></p>
<h2 id="git-客户端">Git 客户端</h2>
<p><a href="https://git-scm.com/">Git 官方客户端</a>
<a href="https://tortoisegit.org/">TortoiseGit</a>
<a href="https://www.sourcetreeapp.com/">SourceTree</a></p>
<h2 id="初始设置">初始设置</h2>
<p>设置姓名和邮箱地址
首先设置使用 Git 时的姓名和邮箱地址。名字请用英文输入。<code>--global</code> 为全局设置参数。</p>
<pre tabindex="0"><code>$ git config --global user.name "<用户名>"
$ git config --global user.email "<用户邮箱>"
</code></pre><p>这个命令,会在 “~/.gitconfig” 中以如下形式输出设置文件。</p>
<pre tabindex="0"><code>[user]
name = <用户名>
email = <用户邮箱>
</code></pre><h2 id="git-命令">Git 命令</h2>
<h3 id="初始化仓库">初始化仓库</h3>
<pre tabindex="0"><code>$ git init #初始化仓库
$ git status #查看仓库状态
$ git status -s #查看简单版仓库的状态
$ git show #显示某次提交的内容
</code></pre><h3 id="添加">添加</h3>
<pre tabindex="0"><code>$ git add #向暂存区中添加文件
$ git add . #添加当前目录下的所有文件
$ git add <filename> #添加 <filename> 文件
$ git add -i #交互式添加文件到暂存区
$ git add -p #交互式的保存和取消保存变化
</code></pre><h3 id="提交">提交</h3>
<pre tabindex="0"><code>$ git commit #提交仓库的历史记录
$ git commit -m "<comment>" #以<comment>作为提交操作的介绍信息进行提交
$ git commit --amend #与上次 commit 合并
$ git commit #在编辑器中记述提交信息的格式如下。
#第一行:用一行文字简述提交的更改内容
#第二行:空行
#第三行以后:记述更改的原因和详细内容
</code></pre><p><img src="https://ooo.0o0.ooo/2016/10/27/5811f7fea74ee.png" alt="git三棵树">
(Source:<a href="http://rogerdudler.github.io/git-guide/index.zh.html">罗杰·杜德勒</a>)</p>
<h3 id="日志">日志</h3>
<pre tabindex="0"><code>$ git log #查看提交日志
$ git log --pretty=short #只显示提交信息的第一行
$ git log -p <filename> #显示文件 <filename> 的改动
$ git log -5 #显示 5 条日志
$ git log <分支名> #查看某分支的日志
</code></pre><h4 id="查看某一文件的历史改动">查看某一文件的历史改动</h4>
<p>上述命令中 <code>git log -p</code> 可实现查看某一文件的历史改动,不过在 terminal 里面看文本修改为免太不爽,可以试试 <code>gitk</code> 命令:</p>
<pre tabindex="0"><code>$ gitk <filename>
$ gitk <file_path>
</code></pre><p>在查看时文件历史时可以在命令中添加 --follow 参数跟踪文件一切变动,使用此命令时,如果查看的特定文件文件曾重命名,也将被跟踪到并输出历史改动</p>
<h4 id="查找包含特定文件的-commit">查找包含特定文件的 commit</h4>
<pre tabindex="0"><code>$ git log <filename>
$ git show <commit_id>
$ git log --follow <文件绝对路径>
</code></pre><h3 id="比较">比较</h3>
<p><code>HEAD</code> 表示上一次 commit 的版本
<code>HEAD~n</code> 表示前第 n 次 commit 的版本</p>
<pre tabindex="0"><code>$ git diff #查看更改前后的差别
$ git diff HEAD #查看工作树和最新 commit 的差别
$ git diff HEAD~1 HEAD #比较上一次和这一次代码之间的差异
$ git diff HEAD~3 HEAD #比较前第三次和这一次代码之间的差异
$ git diff HEAD^^^^^ HEAD #比较前第五次和这一次代码之间的差异
$ git checkout -- <filename> #回滚到修改前的状态
</code></pre><p>养成这样一个好习惯:在执行 git commit 命令之前先执行 git diff HEAD 命令,查看本次提交与上次提交之间有什么差别,等确认完毕后再进行提交。这里 HEAD 是指向当前分支中最新一次提交的指针。</p>
<h3 id="回退">回退</h3>
<pre tabindex="0"><code>$ git reset HEAD filename #从暂存区移除文件
$ git reset --hard HEAD~n #直接回退到前第 n 个版本。
$ git reset --hard SHA #回到 SHA 对应的 commit 的版本。
</code></pre><p>可选参数:
<code>–hard</code> 回退版本,代码也回退,忽略所有修改
<code>–soft</code> 回退版本,代码不变,回退所有的 add 操作
<code>–mixed</code> 回退版本,代码不变,保留 add 操作</p>
<h3 id="分支">分支</h3>
<pre tabindex="0"><code>$ git branch <分支名> #以 <branch-name> 为名创建新分支
$ git branch -d <分支名> #删除分支
$ git branch –merged & git branch –no-merged #返回已合并或未合并的分支列表
$ git checkout <分支名> #切换分支
$ git merge #与本地当前分支合并。
$ git merge <分支名> #合并分支到当前分支
</code></pre><p><img src="https://ooo.0o0.ooo/2016/10/27/5811f85386747.png" alt="合并分支">
(Source:<a href="http://rogerdudler.github.io/git-guide/index.zh.html">罗杰·杜德勒</a>)</p>
<h3 id="远程仓库操作">远程仓库操作</h3>
<pre tabindex="0"><code>$ git clone <远程仓库网址> <本地目录名> #将远程仓库克隆到本地
$ git clone -b <分支名> <远程仓库网址> <工作目录名> #克隆远程仓库的特定分支=
$ git clone -o <自定义仓库名> <远程仓库网址> #克隆远程仓库并自定义其名称
$ git fetch <远程仓库名> #从远程库抓取数据
$ git fetch <远程仓库名> <分支名> #从远程库抓取特定分支的数据
$ git remote #查看当前远程库
$ git remote -v #查看远程仓库详细信息
$ git remote <远程仓库名> #查看远程仓库
$ git remote show <远程仓库名> #查看远程仓库信息
$ git remote add <远程仓库名> <远程仓库网址> #添加远程仓库
$ git remote rename <远程仓库名> <新远程仓库名> #重命名远程仓库
$ git remote update <远程仓库名> #更新分支列表
$ git remote rm <远程仓库名> #删除远程仓库
$ git remote add <别名> <远程仓库网址> #设置远程仓库别名
$ git remote prune origin #删除任何不存在于远端仓库的分支
$ git pull #拉取远程库默认分支并合并到当前仓库,相当于 fetch+merge
$ git pull -b <分支名> #拉取远程库特定分支并合并到当前仓库
$ git push origin master #推送数据到默认的远程仓库的主分支
$ git push origin <分支名> #推送数据到默认的远程仓库的特定分支
$ git push origin --tags #推送数据到默认的远程仓库的特定分支并添加标签
$ git push <远程仓库名> <分支名> #推送数据到远程仓库的特定分支
$ git push -u <远程仓库名> <分支名> #指定远程仓库名和分支名为默认值
$ git push -f <远程仓库名> <分支名> #推送数据并强制覆盖到远程仓库的特定分支
$ git push <远程仓库名> <本地分支名>:<远程分支名> #推送数据到远程仓库的特定分支,后者不存在时则新建。
</code></pre><h3 id="其他">其他</h3>
<pre tabindex="0"><code>$ git tag #列出所有标签
$ git tag -a <标签名> -m "<提交信息>" #为版本打一个标签
$ git reflog #显示本地已完成的操作列表
$ git shortlog -sn #显示提交记录的参与者列表
$ git help #帮助文档
$ git reset #撤销上一次 git add . 操作
$ gitk #打开图形化 git 界面
$ git config --global color.ui auto #彩色的 git 输出
$ git config format.pretty oneline #显示历史记录时,每个提交的信息只显示一行
</code></pre><p><img src="https://ooo.0o0.ooo/2016/10/27/5811f9b6e7c76.png" alt="Git 知识结构">
(Source:<a href="http://7xifb5.com1.z0.glb.clouddn.com/wustrive-hexogit%E7%9F%A5%E8%AF%86%E7%BB%93%E6%9E%84.png">wustrive2008</a>)</p>
<h3 id="gitignore">gitignore</h3>
<p>对于 Git 项目中不想进行跟踪、同步的文件 / 目录,可将其写入 <code>gitignore</code> 文件中。在 Github 上有人整理了各种开发配置下的 <code>gitignore</code> 文件模板,你可以 <a href="https://github.com/github/gitignore">在这里</a> 进行挑选。</p>
<h2 id="qa">Q&A</h2>
<h3 id="添加-ssh-密钥对">添加 SSH 密钥对</h3>
<p>操作远程库(clone/push/pull)时产生如下提示 :</p>
<pre tabindex="0"><code> Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.
</code></pre><p>这是由于没有将 SSH 密钥对添加到本地 ssh-agent 和 Github 中导致的。如想了解 ssh-agent 原理,可阅读 <a href="http://yijiebuyi.com/blog/4b5c272e7058cb331098250c8e98eb3e.html">ssh-agent 与 ssh 的区别</a>,可进行如下操作:</p>
<p>1.确保你已经生成了 SSH 密钥对
2.使用 Git Bash,打开 ssh-agent:</p>
<pre tabindex="0"><code>$ eval "$(ssh-agent -s)"
Agent pid 59566
</code></pre><p>3.添加 SSH 密钥对,默认密钥文件名为 <code>id_rsa</code> 和 <code>id_rsa.pub</code>,可根据需要修改密钥文件名:</p>
<pre tabindex="0"><code>$ ssh-add ~/.ssh/id_rsa
Identity added: /c/Users/<用户名>/.ssh/id_rsa (/c/Users/<用户名>/.ssh/id_rsa)
</code></pre><p>4.登录 Github 用户设置界面,进入 SSH 和 GPG 密钥对界面,将本地的 SSH 公钥(*.pub文件)中的内容复制添加到 Github 的 New SSH key 窗口的 key 中,即可添加成功。</p>
<p>ps. 可在根目录中的 .bash_profile 文件(即 ~/.bash_profile)添加命令别名,今后即可使用别名 <code>sshadd</code> 完成上述操作:</p>
<pre tabindex="0"><code>$ alias sshadd='eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_rsa'
</code></pre><p>或者在该文件中添加如下命令,今后打开 git bash 时即可自动完成上述关于 SSH 密钥的操作:</p>
<pre tabindex="0"><code>$ eval "$(ssh-agent -s)" && ssh-add ~/.ssh/github_rsa
</code></pre><h3 id="git-的代理设置">Git 的代理设置</h3>
<p>在对 Github 某仓库进行 git clone 操作时发现,由于身处强国,下载速度极其不稳定,时快时慢甚至断流导致 clone 失败。所以想到为 Git 设置代理解决问题。
这也算是一个大众问题了,从 <a href="https://gist.github.com/laispace/666dd7b27e9116faece6">这里</a> 看到了答案:</p>
<ol>
<li>
<p>确认自己使用的代理工具在本地监听的端口 <code><localport></code></p>
</li>
<li>
<p>在 git bash 中运行如下命令:</p>
<pre tabindex="0"><code>$ git config --global https.proxy http://127.0.0.1:<localport>
$ git config --global https.proxy https://127.0.0.1:<localport>
</code></pre><p>这样就可以使用 http 或 https 的 URL 进行 clone 操作。
如果需要取消代理设置:</p>
<pre tabindex="0"><code>$ git config --global --unset http.proxy
$ git config --global --unset https.proxy
</code></pre></li>
</ol>
<p>在 Git 官网的 <a href="https://git-scm.com/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-%E9%85%8D%E7%BD%AE-Git#_git_config">git-config 页面</a> 看到了这样一段话:</p>
<blockquote>
<p>可以用 git config 配置 Git。</p>
<p>Git 使用一系列配置文件来保存你自定义的行为。 它首先会查找 <code>/etc/gitconfig</code>文件,该文件含有系统里每位用户及他们所拥有的仓库的配置值。 如果你传递 <code>--system</code> 选项给 <code>git config</code>,它就会读写该文件。</p>
<p>接下来 Git 会查找每个用户的 <code>~/.gitconfig</code> 文件(或者 <code>~/.config/git/config</code> 文件)。 你可以传递 <code>--global</code> 选项让 Git 读写该文件。</p>
<p>最后 Git 会查找你正在操作的版本库所对应的 Git 目录下的配置文件(<code>.git/config</code>)。 这个文件中的值只对该版本库有效。</p>
<p>以上三个层次中每层的配置(系统、全局、本地)都会覆盖掉上一层次的配置,所以 <code>.git/config</code> 中的值会覆盖掉 <code>/etc/gitconfig</code> 中所对应的值。</p>
<p>[NOTE]
Git 的配置文件是纯文本的,所以你可以直接手动编辑这些配置文件,输入合乎语法的值。 但是运行 <code>git config</code> 命令会更简单些。</p>
</blockquote>
<p>所以我们可以用 <code>git config --help</code> 命令打开帮助页面,研究一下 <code>git config</code> 中各种命令的用途,然后按格式添加在根目录中的 <code>.gitconfig</code> (即 ~/.gitconfig)文件中。比如对照上述设置代理的配置可按如下格式添加:</p>
<pre tabindex="0"><code>[http]
proxy = http://127.0.0.1:1080
[https]
proxy = http://127.0.0.1:1080
</code></pre><p>关于 <code>.gitconfig</code> 应该还有很多玩儿法,如果你有什么好思路不妨在评论区分享给大家。</p>
<h3 id="git-多账户">Git 多账户</h3>
<p><strong>Git 使用邮箱进行身份验证</strong>,所以 Git 多账户存在以下使用情景:</p>
<ul>
<li>同一台电脑可有多个使用相同邮箱的 Git 账号,密钥默认读取 id_rsa。 为实现在不同网站以<strong>不同用户名,相同邮箱</strong>进行操作,可编辑 <code>~/.ssh/config</code> :</li>
</ul>
<pre tabindex="0"><code>host github
hostname github.com
Port 22
host gitlab
hostname gitlab.zjut.com
Port 65095
</code></pre><ul>
<li>同一台电脑可有多个使用不同邮箱的 Git 账号,web1 使用 id_rsa 密钥,web2 使用 id_rsa_github 密钥。为实现在不同网站以<strong>不同用户名,不同邮箱</strong>进行操作,可进行如下操作:</li>
</ul>
<p>1.编辑 <code>~/.ssh/config</code> :</p>
<pre tabindex="0"><code>## web1
Host web1
HostName gitlab.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa
User name1
## web2
Host web2
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_github
User name2
</code></pre><p>2.取消用户名和邮箱地址的全局设置</p>
<pre tabindex="0"><code>$ git config --global --unset user.name
$ git config --global --unset user.email
</code></pre><p>3.进入每个项目单独设置自己的用户名和邮箱地址</p>
<pre tabindex="0"><code>$ git config user.name "<用户名>"
$ git config user.email "<用户邮箱>"
</code></pre><p>4.测试是否配置成功</p>
<pre tabindex="0"><code>$ ssh-T git@gitlab.com #使用 HostName 测试
$ ssh-T git@web2 #使用 Host 测试
</code></pre><h3 id="更新-github-中-fork-的项目">更新 Github 中 fork 的项目</h3>
<p>在 Github 上 fork 了一些牛人的项目,但自己 fork 的项目是静止不变的,不会随原项目的更新而更新。当原项目更新时,我们可使用如下方法更新自己仓库中相应的项目:
1.克隆自己的项目到本地:</p>
<pre tabindex="0"><code>$ git clone <自己的远程仓库网址>
</code></pre><p>2.进入克隆到本地的项目目录,把 fork 的原项目作为一个远程仓库以 upstream 为别名添加到本地库中:</p>
<pre tabindex="0"><code>$ git remote add upstream <原远程仓库网址>
</code></pre><p>3.拉取另一个远程仓库的相应分支合并到本地库:</p>
<pre tabindex="0"><code>$ git pull upstream master
</code></pre><p>4.将合并后的项目推送到 Github 上自己的项目中:</p>
<pre tabindex="0"><code>$ git push origin master
</code></pre><h3 id="追加改动的-commit">追加改动的 commit</h3>
<p>当完成某一次 commit 后又进行了代码改动,但不想再提交一个新的 commit,这时可以使用如下命令追加改动文件到前一个 commit:</p>
<pre tabindex="0"><code>$ git add <文件名> #将修改的文件添加到暂存区
$ git commit --amend -C HEAD #追加改动到上一次 commit
</code></pre><h3 id="暂时处理其他项目的修改">暂时处理其他项目的修改</h3>
<p>当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。这时候可以将现场储藏起来,然后处理插队需求或切换到其他分支工作,之后再将现场取出继续工作:</p>
<pre tabindex="0"><code>$ git stash #储藏现场以便之后继续工作
$ git stash list #查看所有被储藏的现场列表
$ git stash apply #恢复现场,但是不删除现场备份
$ git stash pop #恢复现场,同时删除现场备份
$ git stash drop #删除现场备份
</code></pre><p>可以从 pop 关键字看出储藏结构是堆栈,因此你可以在这个上面玩儿出其他花样。</p>
<h3 id="使用外部软件进行-diffmerge">使用外部软件进行 diff/merge</h3>
<p>作为一个伪程序狗,终究还是不能逃脱使用 GUI 的宿命。由于 Git 自带的 <code>git diff</code> 并不能够满足某些场景下的使用。我们需要设置一些第三方对比软件进行新旧文档的比较 / 合并。这里笔者使用 Beyond Compare 4 进行举例:</p>
<p><code>git diff</code> 是普通的逐行对比命令,使用外部比较工具需要使用 <code>git difftool</code> 命令,假设 Beyond Compare 4 已安装至 <code>E:\Program Files\Beyond Compare 4</code> 目录,在使用前我们需进行如下配置,方法有二:</p>
<ol>
<li>执行 Git 命令进行配置:</li>
</ol>
<pre tabindex="0"><code>$ git config --global diff.tool bc4
$ git config --global difftool.bc4.path "e:/program files/beyond compare 4/bcomp.exe"
$ git config --global merge.tool bc4
$ git config --global mergetool.bc4.path "e:/program files/beyond compare 4/bcomp.exe"
</code></pre><ol start="2">
<li>修改 <code>. gitconfig</code> 文件进行配置,添加如下项:</li>
</ol>
<pre tabindex="0"><code>[diff]
tool = bc
[difftool]
prompt = false
[difftool "bc"]
path = e:/program files/beyond compare 4/bcomp.exe
[merge]
tool = bc
[mergetool "bc"]
path = e:/program files/beyond compare 4/bcomp.exe
</code></pre><h2 id="tips">Tips</h2>
<p>列举一些实用的 Alias,可根据自己需要酌情修改,并将其写入 <code>.bash_profile</code> 文件中实现自动加载:</p>
<pre tabindex="0"><code>alias g=git
alias ga='git add'
alias gaa='git add --all'
alias gap='git add --patch'
alias gb='git branch'
alias gba='git branch -a'
alias gbr='git branch --remote'
alias gc='git commit -v'
alias 'gc!'='git commit -v --amend'
alias gca='git commit -v -a'
alias 'gca!'='git commit -v -a --amend'
alias gcl='git config --list'
alias gclean='git reset --hard && git clean -dfx'
alias gcm='git checkout master'
alias gcmsg='git commit -m'
alias gco='git checkout'
alias gcount='git shortlog -sn'
alias gcp='git cherry-pick'
alias gcs='git commit -S'
alias gd='git diff'
alias gdc='git diff --cached'
alias gdt='git difftool'
alias gg='git gui citool'
alias gga='git gui citool --amend'
alias ggpnp='git pull origin `git rev-parse --abbrev-ref HEAD` && git push origin `git rev-parse --abbrev-ref HEAD`'
alias ggpull='git pull origin `git rev-parse --abbrev-ref HEAD`'
alias ggpur='git pull --rebase origin `git rev-parse --abbrev-ref HEAD`'
alias ggpush='git push origin `git rev-parse --abbrev-ref HEAD`'
alias gignore='git update-index --assume-unchanged'
alias gignored='git ls-files -v | grep "^[[:lower:]]"'
alias git-svn-dcommit-push='git svn dcommit && git push github master:svntrunk'
alias gk='gitk --all --branches'
alias gl='git pull'
alias glg='git log --stat --max-count=10'
alias glgg='git log --graph --max-count=10'
alias glgga='git log --graph --decorate --all'
alias glo='git log --oneline --decorate --color'
alias globurl='noglob urlglobber '
alias glog='git log --oneline --decorate --color --graph'
alias glp=_git_log_prettily
alias gm='git merge'
alias gmt='git mergetool --no-prompt'
alias gp='git push'
alias gpoat='git push origin --all && git push origin --tags'
alias gr='git remote'
alias grba='git rebase --abort'
alias grbc='git rebase --continue'
alias grbi='git rebase -i'
alias grep='grep --color=auto --exclude-dir={.bzr,.cvs,.git,.hg,.svn}'
alias grh='git reset HEAD'
alias grhh='git reset HEAD --hard'
alias grmv='git remote rename'
alias grrm='git remote remove'
alias grset='git remote set-url'
alias grt='cd $(git rev-parse --show-toplevel || echo ".")'
alias grup='git remote update'
alias grv='git remote -v'
alias gsd='git svn dcommit'
alias gsps='git show --pretty=short --show-signature'
alias gsr='git svn rebase'
alias gss='git status -s'
alias gst='git status'
alias gsta='git stash'
alias gstd='git stash drop'
alias gstp='git stash pop'
alias gsts='git stash show --text'
alias gts='git tag -s'
alias gunignore='git update-index --no-assume-unchanged'
alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1'
alias gup='git pull --rebase'
alias gvt='git verify-tag'
alias gwc='git whatchanged -p --abbrev-commit --pretty=medium'
alias gwip='git add -A; git ls-files --deleted -z | xargs -r0 git rm; git commit -m "--wip--"'
alias gad='git diff --name-only --diff-filter=M --relative | xargs -rt git add'
alias log="git log --oneline --graph --decorate --color=always"
alias logg="git log --graph --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)' --abbrev-commit --date=relative"
</code></pre><p><img src="https://ooo.0o0.ooo/2016/08/27/57c1c74738dc1.png" alt="Git Cheat Sheet"></p>
<hr>
<p><strong>相关文章</strong>
<a href="http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000">廖雪峰Git系列教程</a>
<a href="http://www.php-z.com/blog-200052-112.html">Git 学习之基本操作(一)</a>
<a href="http://www.php-z.com/blog-200052-105.html">Git 入门</a>
<a href="http://www.php-z.com/blog-200052-106.html">Git 安装和初始设置</a>
<a href="https://www.sdk.cn/news/2957">常用的 12 个 Git 基本命令</a>
<a href="http://www.jianshu.com/p/d1c9bfa612db">git 和 svn diff 命令行可视效果</a>
<a href="http://www.kuqin.com/shuoit/20151010/348440.html">关于 Git 和 Github 你不知道的十件事</a>
<a href="https://wsgzao.github.io/post/git/">Git 常用命令和 Git 团队使用规范指南</a>
<a href="https://gist.github.com/suziewong/4378434">Git 的多账号如何处理?</a>
<a href="http://liujin.me/blog/2015/05/25/Git-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Git 常用命令</a>
<a href="http://www.barretlee.com/blog/2014/05/07/cb-git-improve/">git版本管理策略及相关技巧(A)</a></p>
《关键词》读书笔记
https://acuario.xyz/others/keywords-clip/
2023-09-27T18:25:39+00:00
2016-05-16T20:25:16+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<h3 id="序">序</h3>
<p>公知作为一个缩略的名词本身是不会被污名化的行为所玷污的,一个觉得要污名化公共知识分子的社会,正是最需要公共知识分子的社会。</p>
<h3 id="关系">关系</h3>
<p>当前中国最大的问题不是缺乏常识,而是常识的矛盾;不是价值的虚无,而是价值观念与社会现实之间的断裂。</p>
<h3 id="冷漠">冷漠</h3>
<p>有些前苏联和东欧国家的知识分子形容他们当年面对的政体是一种“不道德的政治”,理由是人民的冷漠、互不关怀和良心的虚无,恰恰乃政权所需;他们不是怕你没良知,只怕你太热心。然而吊诡的是,你又不可能长久而稳定地管治一群什么都不相信的人。一个彻底原子化的社会,注定是要瓦解的。所以1987年那一年,苏联媒体上最常见的一句话是“我们不可能再这样子下去了”。</p>
<h3 id="泄愤杀人">泄愤杀人</h3>
<p>最叫我震惊和不解的,更是大多数人对近年诸多“泄愤杀人”案之解释的轻易接受。似乎我们都以为杀人不难,生命易损。就像坊间流行的《大秦帝国》那一类书,不只轻描淡写地略过“坑赵卒五十万”背后的残酷血腥,更要歌颂其雄壮“大气”。这么一个把杀人看得很容易很不难理解的国家是可怕的。</p>……
<h3 id="序">序</h3>
<p>公知作为一个缩略的名词本身是不会被污名化的行为所玷污的,一个觉得要污名化公共知识分子的社会,正是最需要公共知识分子的社会。</p>
<h3 id="关系">关系</h3>
<p>当前中国最大的问题不是缺乏常识,而是常识的矛盾;不是价值的虚无,而是价值观念与社会现实之间的断裂。</p>
<h3 id="冷漠">冷漠</h3>
<p>有些前苏联和东欧国家的知识分子形容他们当年面对的政体是一种“不道德的政治”,理由是人民的冷漠、互不关怀和良心的虚无,恰恰乃政权所需;他们不是怕你没良知,只怕你太热心。然而吊诡的是,你又不可能长久而稳定地管治一群什么都不相信的人。一个彻底原子化的社会,注定是要瓦解的。所以1987年那一年,苏联媒体上最常见的一句话是“我们不可能再这样子下去了”。</p>
<h3 id="泄愤杀人">泄愤杀人</h3>
<p>最叫我震惊和不解的,更是大多数人对近年诸多“泄愤杀人”案之解释的轻易接受。似乎我们都以为杀人不难,生命易损。就像坊间流行的《大秦帝国》那一类书,不只轻描淡写地略过“坑赵卒五十万”背后的残酷血腥,更要歌颂其雄壮“大气”。这么一个把杀人看得很容易很不难理解的国家是可怕的。</p>
<h3 id="无知">无知</h3>
<p>知识分子或者自诩为比较有常识的人常常容易忽略某些基层的处境,甚至讪笑在他们眼中很不可思议的行为。因为我们的眼睛被安定感遮蔽了,使我们看不到这个世界还有太多人活得不像我们这么安稳。</p>
<h3 id="炫富">炫富</h3>
<p>英国流行病学专家理查德·威尔金森(Richard Wilkinson)和凯特·皮克特(Kate Pickett)在他们那本广受好评的《不平等的痛苦》(The Spirit Level)中提到:“伴随着焦虑水平的上升,自恋也随之上升,二者拥有共同的根源。它们都是由所谓的‘社会评价威胁’的增加引起的。”简单地说,“社会评价威胁”是一种身份焦虑,把自己的尊严完全建立在其他人的评价之上,一天到晚就在担心人家瞧不起自己。根据这两位学者的比较研究,他们发现一个社会越是不平等,其成员就越是忧虑他人对自己的看法。在一个极端不平等的社会里面,大家既会用消费来增加自信,想让他人看得起自己;也会因为在炫耀性消费面前自惭形秽,觉得自己被人贬低贱视。</p>
<h3 id="媚俗">媚俗</h3>
<p>无论是从字面意义还是引申意义讲,媚俗是把人类生存中根本不予接受的一切都排除在视野之外。”</p>
<h3 id="个别">个别</h3>
<p>所有从事文艺创作的人都明白,哀鸿遍野还及不上一只孤雁回旋那么动人。想要诱发观者的情绪,你就得掌握一套关于具体的修辞学,因为人类不因普遍与抽象的事物而动情。同样,政客演讲与其大抛数字,还不如说点小故事;与其让我们知道有几十万人活在贫困线下,还不如细致地描绘一个贫困家庭的日常生活。</p>
<p>“个别事件”在公关修辞学里的唯一作用,就是抽空真实的个别事件。对于一部小说或者一部电影来说,“个别”意味着更具体更丰富,因此也变得更加动人的故事;对于政客而言,“个别”却是抽象和贫血的同义词。</p>
<h3 id="模式">模式</h3>
<p>在黑格尔的年代,哲学的问题是它总是来得太迟了;在我们这个年代,哲学的问题却是它总是来得太早。</p>
<h3 id="国情">国情</h3>
<p>国情既是一国的现实,也是该国国民对这种现实状况的认知和判断。
现实和理想本该有所差异,每一个时代的人都会觉得自己身处最坏的时代,每一个社会的成员也都会嫌恶自己的社会不够完美,由是批判,由是改变,人类方有进步可言。
总是用国情挡掉一切外来批评,固然有套文化相对论的基础;却也是对理想的否定,因为它同时还挡掉了国民内部的不满。这是以国情的现实面消解了国情的理想面,等于是在告诉人民“这已经是最好的情况,最理想的社会,不可能再好了”;如果有人想要更理想的社会,那他的理想一定是源自外国的舶来品。</p>
<p>从前我们高扬理想无视现实,深信脚下大地是实现完美蓝图的一张白纸;现在我们标举现实漠视理想,甚至还把现实升华为理想,要大家像拥抱理想般地拥抱现实。近年学术界中种种“中国模式”的论说便颇有这番把现实变成理想的味道,仿佛我们摸着石头过河摸了半天,原来已经一步步走出了之前无人料及的理想天地。而舆论界中最堪代表的例子,则是《环球时报》那篇有名的社论,它宣称“中国腐败无法通过打击或者通过改革来消除……这是一个根植于社会发展整体水平的问题”,所以“适度腐败”也不妨接受。
以前大家反腐,是因为大家有一个社会不该腐败的理想;如今我们应该顺从国情,不只承认腐败的现实存在,还要接受它。不努力以理想拉拔现实,反而想把理想拖回现实的泥沼,我不晓得,这是否也是我国的独特国情。</p>
<h3 id="美国也有">美国也有</h3>
<p>“美国也有”所诉诸的似乎是种很古怪的“普世价值”:我有喜欢骗人的毛病,他们也有,所以欺骗是很普遍很常见的人类行为;既然普遍,于是正常,欺骗也就因此算不上是坏事了。这种小学生似的逻辑,从前也谈过,不再赘言。但我想指出,相信这类负面“普世价值”的人,恰巧往往也是平日最喜欢用“国情不同”和“文化差异”来说事的人,恰巧也是平日最视普世价值为仇雠的同一群人。当人家物议中国网络和通信监察制度的时候,他们就说个人隐私等西方“普世价值”不能照搬到我们身上,因为我们的国情特殊,对国家安全的理解有自己的特色。等到“斯诺登事件”爆发,他们一方面奇怪地站回捍卫隐私的“普世”角度去抨击美国;另一方面却又反过来标举负面的“普世价值”,告诉大家西方人一样侵犯隐私。他们到底想说什么?又到底相信什么呢?
假如你真的认为个人通信隐私不容政府侵犯,那你就应该用同样的标准去要求所有国家,不可动辄高谈国情分别;假如你真的认为个人隐私应该让路给国家安全,那么这时候你就应该大力声援美国政府,夸赞它干得好,而不是反过来加入抨击他们的阵营。</p>
<p>一个美国人对着一个苏联人炫耀:“我们有言论自由,我可以臭骂美国政府。”那个苏联人听了之后很不屑地回道:“那有什么了不起,我们一样可以臭骂美国政府。”</p>
<h3 id="近视">“近视”</h3>
<p>我们不得不承认,就算优酷、开心网与新浪微博的功能再强大,使用者的数量再多,也始终不是一个世界性的平台。你可以关起门来在上面玩得不亦乐乎,甚至期盼它们有朝一日会成为真正全球共享的工具;但是这一刻,你却失去了世界,那种知觉的背景,以及资讯流动的真正边界。
今天的中国是一个大国,却像一个不知道自己有近视的大个子,人人都怕他,可他看不清其他人一目了然的角落与障碍,也看不见人家的神色。为什么他不能跑去配一副度数合宜的眼镜呢?</p>
<h3 id="围观">围观</h3>
<p>目光与舆论之所以有效,是因为管治者和被管治的社会就像一具机器和它身处的环境一样,前者总要从后者那里接收反应,然后回馈到既有的机制之中,修正逻辑,再调校自己下一步的行动。我现在最担心的是明明路面越来越坏,满地坑洼,走在上面的汽车却可以不受刺激,继续行驶。这说明那部汽车有自己的强大逻辑,它踩在地上,但不必顾及地面传来的信息和刺激。它和外在环境绝缘,只对内在部件负责,依循自己既定的路线。从某个角度来讲,你也可以说它是辆很有威力的好车。</p>
<h3 id="大众传播">大众传播</h3>
<p>传统新闻媒体掌握了定义新闻的权力,它可以判断什么算作新闻,什么不算;而它用以判断的标准往往是很可疑的。比如说同样是死人,为什么我们总是能在国际新闻上头看到一个美国疯汉活活把人咬死之类的故事,却听不到每天甚至每一分钟都发生在南方世界的儿童饿死的消息呢?如果在一些媒体受到威权掌控的国家,官方定夺了新闻的定义和范围,我们大概就会读到连篇累牍的领导人动向,却不晓得社会底层备受压迫折磨的不公遭遇了。所以我们期待每一个人都能做记者的时代,期待每一个人都有能力和权力去发布他们看见的事实,让我们知晓新闻定义之外的新闻。</p>
<p>在满足民众知情权的前提底下,传统媒体也该慢慢懂得知情权与好奇心之间的差异;民众好奇的东西不一定是他们有权知道的事情,例如一个性侵犯受害者的身份。</p>
<p>拍摄和上传这些资讯的网民有没有想过这么做的后果?他们有没有发现自己手握便利的电子记录工具,拥有推特、脸书和微博等仿如媒体的大众平台,其实就已经是个公民记者甚至是个独家的新闻社?更重要的是,他们有没有反省过掌握这些工具平台就等于掌握了权力,甚至武器,因此就该负有相应的道德责任?</p>
<p>任何人都是新闻的供应者,任何人也都是新闻中的角色。这个时代才刚刚开始,要学懂其中的伦理规范和分寸拿捏,恐怕还有很长的一段路。</p>
<h3 id="专业">专业</h3>
<p>新闻自由不是个体的为所欲为,而是集体的自主能力。真正的新闻自由与专业伦理的自律,根本是不可分割的同一回事。</p>
<p>当一整个专业都能坚守原则,并以专业操守为傲,社会大众便会逐渐形成共识,知道这个行业的精神与底线。</p>
<h3 id="脱节">脱节</h3>
<p>假如这想象中最坏的官员都还保有最起码的脆弱良知,为什么最普通的官员都还会给人看到他“政绩第一,人命第二”的决策表现?为什么广州一个地方官员会在慰问舍己救人的消防员家属时说“恭喜你们培养出这么优秀的儿子”呢?如果这位官员家中有人不幸殉职,他能接受得了别人对他的恭喜吗?
从“你是为党说话,还是为老百姓说话”,一直到“反正我是信了”,这一连串的“雷人”官话最能说明我想讨论的问题。在我看来,关键不在于说这些话的官员真是白痴,就如同一个无恶不作的歹官并非真的灭绝了人性一样。真正的要害是一个智力正常、也和你我一样天天活在社会之中的官员,不知怎么的就在某些场合失去了基本的判断能力,说了常人说不出的话,干了常人干不下的事。</p>
<h3 id="权力">权力</h3>
<p>所谓权力,在我们这里就是一种能够真正动用的资源与力量,用了才叫有权,不用就不叫权力了。
那是一个你永远摸不清底细和边界的范围,既用不着告诉你它的深浅,也用不着向你交代它的大小。当它启动,你只能被动地接受,却不能知悉它如何启动,以及启动的时机与规模。你更加不必追问权力究竟有什么存在的必要。</p>
<h3 id="盛事">盛事</h3>
<p>我们或许可以独裁地宣称“必须不顾一切”,那就是战争了。只有战争才会只追求一个目标,可以为了胜利而不计代价(不过,战争也并非真的能够不计代价。也有些国家会比另一些国家重视战时状态的人权,也有些国家会比另一些国家更担忧人命的损伤)。大家在讨论中国某些政策的制定和施行时往往会提到“动员”这两个字,“动员”岂不就是一种作战的准备?它是我们非常熟悉的决策和施政方式,从水利工程到发展经济,有哪一回不是朝着一个目标动员大家努力前进?“盛事”就像战争,它的问题不只是“扰民”,而是根本没想到除了“盛事”之外,原来人民还有其他的利益诉求以及无论何时也不可剥夺的权利。老百姓为什么怕了“盛事”?因为没有人想天天打仗。</p>
<h3 id="宏大">宏大</h3>
<p>有这么多关于坟墓的故事,好些有心人也顺道提起了美国纽约格兰特总统陵墓的故事了。
这故事的重点不在这位南北战争的名将,却在这座陵墓旁一个叫作圣克莱尔·波洛克(St. Clare Pollock)的五岁小男孩身上。
这个小孩死在1797年,随后葬身此地,他的父亲太过伤心,便将整块土地卖了出去,唯一条件是要永久保留爱子的坟墓。
于是经过一代又一代的转手,每一代卖家都要求下一代买主信守当初的诺言,直到1897年美国政府买下,成了它的主人。
照道理讲,百年前的约定对后来的地主没什么约束力了,然而,或者出于信仰,或者受到民意的压力,不管是地产商还是政府,都还是保住了小男孩的墓,并且屡加修葺,使之长伴格兰特总统身侧,至今仍传为佳话。</p>
<p>有些时候,我们太过崇奉很宏大、很抽象的理念,比如说“为国牺牲”,又比如说为了“经济发展”和为了“消除反动遗迹”。你永远可以找到全新的宏大话语,所以你也永远可以掘毁推平一座座小小的墓地。过去的宏大话语,过去的不朽英名,在今天更伟大的需要之下,就是“我们留着没用”的名字了。</p>
<h3 id="兴亡">兴亡</h3>
<p>国家越是扩张,占据的资源和土地越多,贫富差距就变得越大。贫富差距越大,社会就变得更加动荡。要改革,就要伤及既得利益阶层的筋骨,并且手段非常,往往出之一连串不合既存体制法统的惊人举动,最后又以一场又一场的政治暴力告终。</p>
<hr>
<p>以上摘自:
<img src="https://img3.doubanio.com/lpic/s27315794.jpg" alt="《关键词》">
<a href="https://book.douban.com/subject/25886896/">《关键词》</a><br>
作者:梁文道<br>
出版社:中信出版社</p>
Twidere快速设置教程
https://acuario.xyz/posts/Twidere-quick-setup/
2023-09-27T18:25:39+00:00
2016-04-06T14:46:28+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p><a href="https://droid4.us/droid4now/setup-twidere">如何优雅地刷国际版微博</a>一文介绍了 Twidere 的设置方法,以及如何借助 Heroku 等 PaaS 平台搭建代理,实现 Twidere 能够在刷新时拉取图片的方法。但是繁琐的设置 / 配置方法还是不够友好,虽然一键式操作已经省去了我们对各种 PaaS 平台的命令行操作。随着各类奇技淫巧的出现,我们有了新的方法,快速简单地实现 Twidere 的设置,并能在刷推速度上有极大提升,直接从官方 API 拉取自己的各种 Twitter 信息而无需借助代理平台。</p>
<p>实现原理很简单,那就是使用 hosts 进行域名重定向。在此推荐 <a href="http://laod.cn/hosts/2016-google-hosts.html">2016 Google hosts 持续更新</a> 这个网站提供的包含各类站点的 hosts 文件。替换后,你就可以正常地访问 hosts 修改过的网站啦。</p>……
<p><a href="https://droid4.us/droid4now/setup-twidere">如何优雅地刷国际版微博</a>一文介绍了 Twidere 的设置方法,以及如何借助 Heroku 等 PaaS 平台搭建代理,实现 Twidere 能够在刷新时拉取图片的方法。但是繁琐的设置 / 配置方法还是不够友好,虽然一键式操作已经省去了我们对各种 PaaS 平台的命令行操作。随着各类奇技淫巧的出现,我们有了新的方法,快速简单地实现 Twidere 的设置,并能在刷推速度上有极大提升,直接从官方 API 拉取自己的各种 Twitter 信息而无需借助代理平台。</p>
<p>实现原理很简单,那就是使用 hosts 进行域名重定向。在此推荐 <a href="http://laod.cn/hosts/2016-google-hosts.html">2016 Google hosts 持续更新</a> 这个网站提供的包含各类站点的 hosts 文件。替换后,你就可以正常地访问 hosts 修改过的网站啦。</p>
<h2 id="hosts-文件的修改">hosts 文件的修改</h2>
<p>hosts 文件可以进行直接替换或编辑,不同系统 hosts 文件位置有所不同:</p>
<ul>
<li>Windows 系统 hosts 位于 C:\Windows\System32\drivers\etc\hosts</li>
<li>Android(安卓)系统 hosts 位于 /system/etc/hosts</li>
<li>Mac(苹果电脑)系统 hosts 位于 /etc/hosts</li>
<li>iPhone(iOS)系统 hosts 位于 /etc/hosts</li>
<li>Linux 系统 hosts 位于 /etc/hosts</li>
</ul>
<p>PS:由于 hosts 文件属于系统文件,所以修改 hosts 需要对 Android 系统进行 root 操作,对 iOS 系统进行越狱操作。如果你已经完成上述步骤,那么可以自己找一些可用的 hosts 进行修改或替换。如果你的 hosts 设置正确且其重定向的 IP 有效,那么你就可以正常使用官方版本的 Twitter 客户端进行刷推了。</p>
<hr>
<h2 id="bazinga">Bazinga</h2>
<p>如果本文到此结束那真是 too young too simple 了。<span style="color: #ffffff;">你们憋想搞个大新闻,把我批判一番!</span>
下面介绍未 root 的 Android 如何通过 hosts 实现 Twidere 的正常使用。</p>
<h3 id="安装-twidere">安装 Twidere</h3>
<p>Twidere 的 <a href="https://github.com/TwidereProject/Twidere-Android/releases">Github 项目发布页</a> 可下载<strong>最新</strong>版本<br>
twidere-fdroid-release.apk 为开源软件下载站 fdroid 版本<br>
twidere-google-release.apk 为 Google Play 版本<br>
你还可以在其 <a href="https://play.google.com/store/apps/details?id=org.mariotaku.twidere">Google Play</a> 和 <a href="http://www.coolapk.com/apk/org.mariotaku.twidere">酷安</a> 页面进行下载并安装</p>
<h3 id="设置-twidere">设置 Twidere</h3>
<p>(1) 打开 Twidere,点击右上方的第二个图标编辑 API</p>
<p style="text-align: justify; align: center;"><img class="alignnone" src="https://i0.wp.com/ww2.sinaimg.cn/large/68f607d1gw1f2mya4u07rj20x71jedky.jpg?resize=360%2C600" alt="Twidere 初始界面" width="360" height="600"><img class="alignnone" src="https://i2.wp.com/ww2.sinaimg.cn/large/68f607d1gw1f2myh81kmfj20x71jetfk.jpg?resize=360%2C600" alt="编辑 API" width="360" height="600"></p>
<p>(2) 在 API 编辑窗口中进行如下设置,从上到下分别填入:</p>
<blockquote>
<p><a href="https://api.twitter.com/">https://api.twitter.com/</a><br>
3nVuSoBZnx6U4vzUxf5w<br>
Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys</p>
</blockquote>
<p>关于 API 的细节问题,可访问 <a href="https://droid4.us/droid4now/setup-twidere">如何优雅地刷国际版微博</a> 进行了解。</p>
<p>(3) 保存修改后点击初始界面右上角最右侧图标进入设置 - 网络 - 高级</p>
<p><img class="aligncenter" src="https://i1.wp.com/ww4.sinaimg.cn/large/68f607d1gw1f2mysrvooyj20x71jeted.jpg?resize=360%2C600" alt="设置界面" width="360" height="600"></p>
<p>(4) 开启内置 DNS 解析、TCP DNS 查询方式选项(如图四),并设置 DNS 服务器为 8.8.8.8</p>
<p style="text-align: justify;"><img class="alignnone" src="https://i0.wp.com/ww4.sinaimg.cn/large/68f607d1gw1f2mz02q1cbj20x71je10d.jpg?resize=360%2C600" alt="修改连接性 API" width="360" height="600"><img class="alignnone" src="https://i2.wp.com/ww4.sinaimg.cn/large/68f607d1gw1f2myt2hr0rj20x71jejww.jpg?resize=360%2C600" alt="修改 DNS 服务器" width="360" height="600"></p>
<p>(5) 进入自定义主机映射,添加主机名映射:</p>
<blockquote>
<p>主机名为 <code>api.twitter.com</code> <br>
地址为 <code>185.45.5.54</code></p>
</blockquote>
<p style="text-align: justify;"><img class="aligncenter" src="https://i0.wp.com/ww1.sinaimg.cn/large/68f607d1gw1f2n3445ieij20x71jedl4.jpg?resize=360%2C600" alt="自定义主机映射" width="360" height="600"></p>
<p><strong>依次保存并返回初始界面,输入 Twitter 账号密码,体验飞一般的国际版微博吧!</strong></p>
Hello Hexo
https://acuario.xyz/posts/hello-hexo/
2023-09-27T18:25:39+00:00
2016-04-01T00:00:00+00:00
Acuario
https://acuario.xyz/
yhyy135@gmail.com
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)<p>心血来潮重新搭建了一次 Hexo,过程还算顺利。本想着其实网上教程已经足够多了,随便搜一搜就能找到各种详尽的资料和教程,但是当我想起之前看到那条 <a href="https://twitter.com/ruanyf/status/713323072174948354">Twitter</a> 的时候,还是抱以分享的态度去试着写点东西。再此引用全文以激励阅读本文的读者和没有习惯更新博客的自己。</p>
<blockquote>
<p>ruanyf @ruanyf 3 月 25 日<br>
不管你干什么,我都建议经常写作。随便写什么,不一定文辞优美,只需包含对自己领域的一些体会。不要低估写作的力量,它能让你从日常琐事抽身出来,透彻思考心中的问题。最重要的是,写给别人看时,你就成为更广阔世界的一部分。发表文字就是在宣称自己是社会一员,愿意做一些有意义的贡献。# 书摘</p>
</blockquote>……
<p>心血来潮重新搭建了一次 Hexo,过程还算顺利。本想着其实网上教程已经足够多了,随便搜一搜就能找到各种详尽的资料和教程,但是当我想起之前看到那条 <a href="https://twitter.com/ruanyf/status/713323072174948354">Twitter</a> 的时候,还是抱以分享的态度去试着写点东西。再此引用全文以激励阅读本文的读者和没有习惯更新博客的自己。</p>
<blockquote>
<p>ruanyf @ruanyf 3 月 25 日<br>
不管你干什么,我都建议经常写作。随便写什么,不一定文辞优美,只需包含对自己领域的一些体会。不要低估写作的力量,它能让你从日常琐事抽身出来,透彻思考心中的问题。最重要的是,写给别人看时,你就成为更广阔世界的一部分。发表文字就是在宣称自己是社会一员,愿意做一些有意义的贡献。# 书摘</p>
</blockquote>
<h3 id="申请-github-page">申请 GitHub Page</h3>
<ol>
<li>申请 <a href="https://github.com/">GitHub</a> 账号</li>
<li>登录 GitHub 后在主页点击 <code>New repository</code>,在 <code>Repository name</code> 中输入前缀与自己 GitHub 用户名一致的仓库名称 <code>[用户名].github.io </code>。例如,你的用户名为 <code>helloworld</code>,则创建仓库名称为 <code>helloworld.github.io</code></li>
<li>勾选 <code>Initialize this repository with a README</code> 并创建仓库</li>
</ol>
<p>PS:</p>
<ul>
<li>仓库名称前缀若与用户名不一致则无法成功申请 GitHub Page。</li>
<li>仓库属性必须为公开,即必须为 <code>Public</code>。</li>
</ul>
<h3 id="环境准备">环境准备</h3>
<ol>
<li>安装所需的 <a href="https://git-scm.com/downloads">Git Bash</a> 和 <a href="http://nodejs.org/">Node.js</a> 程序</li>
<li>按照 <a href="https://help.github.com/articles/generating-an-ssh-key/">Github 官方教程</a> 生成并添加 SSH 密钥到 Github 设置中。</li>
</ol>
<h3 id="安装部署-hexo">安装&部署 Hexo</h3>
<ol>
<li>运行 Git Bash,使用如下命令安装 Hexo:</li>
</ol>
<pre tabindex="0"><code>$ npm install -g hexo-cli
</code></pre><ol start="2">
<li>安装完成后对 Hexo 进行部署,创建一个文件夹作为 Hexo 工作目录。为避免不必要的麻烦,建议使用英文路径。</li>
<li>运行 Git Bash 并进入 Hexo 工作目录,使用如下命令对 Hexo 进行初始化:</li>
</ol>
<pre tabindex="0"><code>$ hexo init
$ npm install
</code></pre><ol start="4">
<li>安装 Hexo 插件,详细信息可以访问<a href="https://hexo.io/plugins/">插件</a>页面查看相关内容</li>
</ol>
<pre tabindex="0"><code>$ npm install hexo-generator-index --save #首页生成插件
$ npm install hexo-generator-archive --save #归档页生成插件
$ npm install hexo-generator-category --save #分类页生成插件
$ npm install hexo-generator-tag --save #标签页生成插件
$ npm install hexo-renderer-marked --save #Markdown 语法渲染插件
$ npm install hexo-renderer-stylus --save #Stylus 渲染插件
$ npm install hexo-renderer-ejs --save #ejs 渲染插件
$ npm install hexo-server --save #Hexo 本地服务器插件
$ npm install hexo-deployer-git --save #git 部署插件(选装 推荐)
$ npm install hexo-generator-feed --save #feed 生成插件(选装 推荐)
$ npm install hexo-generator-sitemap --save #sitemap 生成插件(选装 推荐)
$ npm install hexo-hey --save #hey 可视化后台编辑插件(选装 推荐)
$ npm install hexo-tag-owl --save #Owl 多媒体插件(选装)
$ npm install hexo-ruby-character --save #萌娘百科注音插件(选装)
$ npm install hexo-generator-search --save #Search 生成插件(选装)
$ npm install hexo-git-backup --save #使用 Github 备份博客(选装)
</code></pre><ol start="5">
<li>执行如下命令,访问 http://localhost:4000 即可本地预览 Hexo 页面</li>
</ol>
<pre tabindex="0"><code>$ hexo server
</code></pre><h3 id="hexo-基本操作">HEXO 基本操作</h3>
<p>HEXO 命令需要在 Hexo 工作目录内运行。</p>
<h4 id="新建文章">新建文章</h4>
<pre tabindex="0"><code>$ hexo new "My New Post" #创建一篇新文章,引号内为标题
</code></pre><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p>
<h4 id="本地预览-hexo-页面">本地预览 Hexo 页面</h4>
<pre tabindex="0"><code>$ hexo server
$ hexo s #命令简写
</code></pre><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p>
<h4 id="生成静态文件">生成静态文件</h4>
<pre tabindex="0"><code>$ hexo generate
$ hexo g #命令简写
</code></pre><p>PS:Hexo 是静态播客生成器,故修改博客内容后都需重新生成静态文件</p>
<p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p>
<h4 id="部署静态文件到远程站点">部署静态文件到远程站点</h4>
<pre tabindex="0"><code>$ hexo deploy
$ hexo d #命令简写
</code></pre><p>More info: <a href="https://hexo.io/docs/deployment.html">Deployment</a></p>
<h4 id="生成静态文件并部署到远程站点">生成静态文件并部署到远程站点</h4>
<pre tabindex="0"><code>$ hexo g -d
</code></pre><h4 id="清除-public-文件夹和数据库">清除 public 文件夹和数据库</h4>
<pre tabindex="0"><code>$ hexo clean
$ rm db.json -f
</code></pre><h3 id="参考资料">参考资料</h3>
<ol>
<li><a href="https://hexo.io/zh-cn/docs/">Hexo 官方文档</a></li>
<li><a href="http://meteoritey.github.io/2015/01/03/hello-world/">Hello Hexo by MeteoriteY</a></li>
</ol>