HTTP访问控制(CORS, Cross-Origin Resource Sharing)

简单来说,CORS请求分为简单请求(非术语)和预检请求(Preflight Request)。

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

使用下列方法之一:

GET

HEAD

POST

Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为:

Accept

Accept-Language

Content-Language

Content-Type (需要注意额外的限制)

DPR

Downlink

Save-Data

Viewport-Width

Width

Content-Type 的值仅限于下列三者之一:

text/plain

multipart/form-data

application/x-www-form-urlencoded

与前述简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS   方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。”预检请求”的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

 

当请求满足下述任一条件时,即应首先发送预检请求:

使用了下面任一 HTTP 方法:

PUT

DELETE

CONNECT

OPTIONS

TRACE

PATCH

人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:

Accept

Accept-Language

Content-Language

Content-Type (but note the additional requirements below)

DPR

Downlink

Save-Data

Viewport-Width

Width

Content-Type 的值不属于下列之一:

application/x-www-form-urlencoded

multipart/form-data

text/plain

对于预检请求,浏览器会先发送一个预检请求给服务端,服务端正常响应(服务器是否同意客户端继续请求)后才会发送实际请求。

References:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

《浪矢解忧杂货店》观影感言

电影根据东野圭吾的同名原作改编,原作之前已经非常有名了,而且之前国内也有改编为电影并且上线,所以这次日本版的电影在大陆一经上线,就和老婆一起去看了。(当然还有一个真相是老婆喜欢的小鲜肉有出演一个角色)

电影开头是有点莫名奇妙,内容很突兀,只有逐渐追随几个故事的发展,才会逐渐了解故事发展的主线,明白人物关系及事件的因果关系。所以对于一个没有看过原著的人来说,据情理解还是有点费心的。而且从全局来看,故事的背景设定有点儿戏,感觉有点纯粹科幻的感觉(主要是故事情节最大的需要:现在和过去的通信)。

但是我仍然要说,这是一部很好的电影(或许应该把这个赞美献给原著)。中日基于相同的文化的发展起来,到现在虽然有很多差异,但是我觉得还是有很多共性,更重要的有很多相似的认同感。很多有名的日剧/电影都有着我们的文化里非常认可的奋斗、励志的形象。而这部电影里的很多场景,很多任务面临的选择都是如此的贴近我们的生活,非常能够触动我们的内心。浪矢雄治给陌生人的回信,是传递了自己的信仰,自己对人生的理解。3个小孩后面给几十年前的人回信也一样,希望收信的人的能够幸福,避开自己的不信,追求自己的梦想,找到适合自己的幸福。当然这碗鸡汤让很多收信人十分不爽,继续写信辩解,让他们自己更加清晰的知道自己需要的是什么,同时这让据情越发的真实了,不是一碗强给的鸡汤。

剧中的一些点是容易获得我们的共鸣: 3个小孩告诉武藤晴美(迷途的幼犬),去炒房炒高尔夫会员卡炒股……让我们这一代人感觉是那么的真实,房价这个这几年迈不开的砍,绕不过去的故事,实时提醒这我们……

影片也提醒了关于小孩教育,赡养老人等方面的一些问题,但不是重点,我也就不展开了。

 

php.ini中的cgi.fix_pathinfo选项

PHP里经常要获取当前请求的URL路径信息。一般可以通过环境变量$_SERVER[‘PATH_INFO’]获取,而配置文件中的cgi.fix_pathinifo选项则与这个值的获取相关。而$_SERVER[‘PATH_INFO’]中的key PATH_INFO是一个CGI 1.1的标准,经常用来做为传递参数给后端的CGI服务器。

被很多系统用来优化url路径格式,比如对于很多框架,下面这个网址:
http://www.test.com/index.php/test/my.html?c=index&m=search
我们可以得到
$_SERVER[‘PATH_INFO’] = ‘/test/my.html’
$_SERVER[‘QUERY_STRING’] = ‘c=index&m=search’;

我们再说下php.ini中的配置参数cgi.fix_pathinfo,它是用来对设置cgi模式下为php是否提供绝对路径信息或PATH_INFO信息。没有这个参数之前PHP设置绝对路径PATH_TRANSLATED的值为SCRIPT_FILENAME,没有PATH_INFO值。设置cgi.fix_pathinfo=1后,cgi设置完整的路径信息PATH_TRANSLATED的值为SCRIPT_FILENAME,并且设置PATH_INFO信息;如果设为cgi.fix_pathinfo=0则只设置绝对路径PATH_TRANSLATED的值为SCRIPT_FILENAME。cgi.fix_pathinfo的默认值是1。
nginx默认是不会设置PATH_INFO环境变量的的值,需要通过正则匹配设置SCRIPT_FILENAME,但这样会带来安全隐患,需要把cgi.fix_pathinfo=0设置为0。但是一旦关闭这个这场,PHP就获取不到PATH_INFO信息,那些依赖PATH_INFO进行URL美化的程序就失效了。
关于安全隐患的问题,请看 http://www.laruence.com/2010/05/20/1495.html

网上给出了一些方案,在关闭cgi.fix_pathinfo时使依赖PATH_INFO美化url的程序能够正常工作。
1.可以通过rewrite方式代替php中的PATH_INFO
实例:thinkphp的pathinfo解决方案
设置URL_MODEL=2
location / {
if (!-e $request_filename){
rewrite ^/(.*)$ /index.php?s=/$1 last;
}
}
2.nginx配置文件中设置PATH_INFO值
请求的网址是/abc/index.php/abc
PATH_INFO的值是/abc
SCRIPT_FILENAME的值是$doucment_root/abc/index.php
SCRIPT_NAME /abc/index.php
旧版本的nginx使用如下方式配置
location ~ .php($|/) {
set $script $uri;
set $path_info “”;

if ($uri ~ “^(.+.php)(/.+)”) {
set $script $1;
set $path_info $2;
}

fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$script;
fastcgi_param SCRIPT_NAME $script;
fastcgi_param PATH_INFO $path_info;
}
新版本的nginx也可以使用fastcgi_split_path_info指令来设置PATH_INFO,旧的方式不再推荐使用,在location段添加如下配置。
location ~ ^.+.php {

fastcgi_split_path_info ^((?U).+.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

}

通过上面的描述,我们似乎得出了一个结论:为了安全要关闭掉cgi.fix_pathinfo设置。
但是我们来看看php.ini的配置及说明

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP’s
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=1

设置cgi.fix_pathinfo=1才符合cgi标准。那么有什么办法可以在保持cgi.fx_pathinfo默认设置的情况下,保证系统安全吗?

好消息,新版本PHP(我验证至少PHP5已经有了这个参数)的fpm配置里新增了一个额外参数(php-fpm.d/www.conf),
security.limit_extensions = .php .php3 .php4 .php5 .php7

专门用来限制PHP脚本引擎只支持解析哪些扩展名的文件

; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; execute php code.
; Note: set an empty value to allow all extensions.
; Default Value: .php
;security.limit_extensions = .php .php3 .php4 .php5 .php7

所以在使用nginx+php-fpm时,可以不用修改系统默认的cgi. fix_pathinfo=1设置了。

References:
http://www.laruence.com/2010/05/20/1495.html

http://www.nginx.cn/426.html

https://serverfault.com/questions/627903/is-the-php-option-cgi-fix-pathinfo-really-dangerous-with-nginx-php-fpm

PHP的print

有这样的一题:

echo ‘2’.print(2)+3;

问输出是多少?

运行结果是……(下面有分析过程及答案,提前预告:正确答案不是224,此题并不涉及运算符优先级https://secure.php.net/manual/en/language.operators.precedence.php

print 实际上不是函数(而是语言结构),所以可以不用圆括号包围参数列表。

print(2) <=> print 2

print (2)+3 <=> print 2+3

所以 echo ‘2’.print(2)+3;  ==> print 2+3先输出5,echo ‘2’.1 输出“21”,所以整体输出521 。

 

类似的情况

echo ‘2’.print(2)+3; //521

echo ‘4’.print(2)+3+1*7; //1241

echo ‘1’.print(2)+3+1*7,33; //121133 注意:逗号会分隔print的参数作用范围

红薯(地瓜)和豆薯(地瓜)

今天我要来说说红薯、凉薯/豆薯、地瓜 这三个名词代表的两个吃的东西~

地瓜这个词在南北方的很多区域表述的不是同一个东西。有的地方是指红薯/番薯,有的地方是指凉薯/豆薯。

番薯(学名:Ipomoea batatas),又名甘薯、地瓜,是常见的多年生双子叶植物,草本,其蔓细长,茎匍匐地面。也指其块根。块根无氧呼吸产生乳酸,皮色发白或发红,肉大多为黄白色,但也有紫色,除供食用外,还可以制糖和酿酒、制酒精。

野生种起源于美洲的热带地区,由印第安人人工种植成功,抗病虫害强,栽培容易。

番薯就是我们平常说的红薯(见下图)

继续阅读红薯(地瓜)和豆薯(地瓜)

聊聊APCU

APCU的前身是APC(Alternative PHP Cache),APC的主要用途有两项:

  1. 将PHP代码编译之后所产生的bytecode暂存在共享内存内供重复使用,以提升应用的运行效率。(Opcode Cache)
  2. 提供用户数据缓存功能。(User Data Cache)

其中第一点是其主要功能,因为PHP的运行机制——每次接受一个请求时都要初始化所有的资源(将源代码转换成Opcode,……),执行代码,然后释放资源;所以启用Opcache Cache后,可以在初始化资源阶段减少CPU和内存的消耗。

但是PHP从PHP 5.5开始,使用ZendOptimizerPlus作为内置的Opcode Cache实现。所以现在APCU的主要功能便不再有意义了,而且其官方也随后表示不再维护APC了。

因此APCU出现了!

APCu is APC stripped of opcode caching.

The first APCu codebase was versioned 4.0.0, it was forked from the head of the APC master branch at the time.

PHP 7 support is available as of APCu 5.0.0.

以上就是关于APCU的前世今生。目前还处于活跃开发中的与APCU类似的工具,还有laruence(鸟哥)开发的Yac。

那么很明确了,APCU就一个功能:用户数据缓存(User Data Cache or Object Caching)。

如何使用APCU嘛,大家看看文档就知道了

https://secure.php.net/manual/en/book.apcu.php

今天要说的是这个APCU缓存和memcahce/redis不一样的地方。你通过memcache/redis存储一个数据,在缓存有效期内,同一机器上的不同的PHP进程(FPM+CLI)都是能够取到这份数据的。

对的,注意关键字 “同一机器上的不同的PHP进程”,对于APCU而言,PHP-FPM模式下所有的php-fpm进程(即使是不同的pool)属于同一个父进程,所以是可以共享缓存数据的;但是cli模式每次都是单独一个全新进程,因而和php-fpm模式的进程是不能共享缓存数据的。所以如果你的业务场景需要在cli和php-fpm两种模式下共享数据一定要小心了,可能memcache或者redis才是你更好的选择。

 

References:

https://github.com/krakjoe/apcu/issues/121

https://github.com/krakjoe/apcu/issues/255

https://github.com/laruence/yac/issues/61

Headless Chrome

Caution: Headless mode is available on Mac and Linux in Chrome 59Windows support is coming in Chrome 60. To check what version of Chrome you have, open chrome://version.

但是经过测试在windows版本的Chrome 60下使用headless命令仍然无效,Ubuntu Desktop下使用Chrome 60是可以的。

可以用下面的一些简单的命令测试:

chrome \
–headless \               # Runs Chrome in headless mode.
–disable-gpu \             # Temporarily needed for now.
–remote-debugging-port=9222 \
https://www.chromestatus.com   # URL to open. Defaults to about:blank.

Create a PDF

The –print-to-pdf flag creates a PDF of the page:

chrome –headless –disable-gpu –print-to-pdf https://www.chromestatus.com/

Taking screenshots

To capture a screenshot of a page, use the –screenshot flag:

chrome –headless –disable-gpu –screenshot https://www.chromestatus.com/

# Size of a standard letterhead.
chrome –headless –disable-gpu –screenshot –window-size=1280,1696 https://www.chromestatus.com/

# Nexus 5x
chrome –headless –disable-gpu –screenshot –window-size=412,732 https://www.chromestatus.com/
Running with –screenshot will produce a file named screenshot.png in the current working directory. If you’re looking for full page screenshots, things are a tad more involved. There’s a great blog post from David Schnurr that has you covered. Check out Using headless Chrome as an automated screenshot tool .

官方给出了几个在 CLI 环境中使用的简单例子,如果需要更复杂的应用,所以可以尝试使用下面这个npm 包编程:https://github.com/cyrus-and/chrome-remote-interface

那么这里要着重说一下,利用chrome的headless模式,需要同时使用Selenium和chromedriver吗?

通过协议直接操作真实浏览器

这就是Selenium的实现方式,通过WebDriver协议进行通信,浏览器和浏览器驱动都实现了C/S结构的WebDriver协议,Selenium通过浏览器的驱动包,来发送操作请求,浏览器根据请求响应相应的操作。这样实现有一个问题是始终有一个真实浏览器的界面在渲染和变化,一方面效率低下,另一方面在服务端环境无法运行。于是就衍生出了使用Xvfb(virtual framebuffer X Server) 来配合实现在服务器环境下的运行,基本解决了问题。但每一种浏览器的特性支持都依赖于相应的驱动的实现和支持情况。

无界面浏览器

前面的实现方式都或多或少有自己的问题或者局限,如果浏览器本身支持在服务端环境运行,这将是一个近乎完美的解决思路。Chrome 59开始支持无界面模式,Firefox 55支持Linux版的无界面模式,Firefox 56支持全平台的无界面模式,这样一来,使用方不用被动等待浏览器的WebDriver的实现。

总结一下:

利用Chrome headless mode,我们可以直接代替以前的Selenium+chromedriver。只是现在没有太多的第三方库封装,可能开发效率不高。但是估计Selenium等软件后续会积极支持的!

PS: PhantomJS原理和chrome headless mode原理差不多,只是chrome的开发团队更为强大,而且PhantomJS的一个核心开发者前一段时间因为Chrome要内置headless mode退出了开发该项目-_-!

References:

https://developers.google.com/web/updates/2017/04/headless-chrome

http://www.jianshu.com/p/aec4b1216011

http://imweb.io/topic/595bbbfdd6ca6b4f0ac71f14

聊聊历史上的行政区划

话说秦并六国后,建立了郡县二级政权的地方行政制度。同时上一篇文章也说到了“州”这个概念,东汉末年“州”正式成为了一个行政,有了州-郡-县三级行政制度。

维基百科的下面这段话很好的解释了郡县的来源:

周武王分封诸侯之时,由于不愿意给诸侯过大的封地,又不愿分封太多的异姓诸侯,导致“有许多地方既非王畿又无适当的人可封”,这些土地“悬而未决”,只能暂时派人管理,等待有合适的人来封,称为“悬之”,后来就演化成了“县”。

春秋时期诸侯兼并,大国灭掉小国之后如不愿将该地分封给大夫,也会设置为县。如楚国就先后将权国、陈国、蔡国灭掉立县。晋国也曾将大夫的封地划分出一块设置为县以加强中央集权。设县主要原因是国土日益变大,如不能分封,中央直接管理也麻烦,所以设置县,交给县尹、县令、县公、县大夫管辖,“使其成为独立的地方政治单位而直属于中央”。所以春秋时期的县只有“晋、楚、秦、齐、吴等大国”有,而小国不需要设县。至战国时代这种制度逐渐为各强国采用,逐渐减少分封于贵族的地区。

秦始皇之前的郡与国防军事有关。郡多设在边境,为防止邻国侵袭则需有大将戍边,集财政大权与一身,直接听命于中央,这样灵活而有战斗力。相当于“军事特别区”。

早期县和郡的关系

县和郡是两种不同的地方政治单位。周朝时县大于郡,《逸周书作雒》:“千里百县,县有四郡”;《左传》哀四年:“克敌者,上大夫受县,下大夫受郡”。但因为郡经常参与战争,郡守比县令有更大的权力,而且新征服的土地设县后往往也要受郡的节制。同时郡守需要有经验有能力的大将担任,普遍比县令能力强。因此郡的地位后来就比县高了。

秦帝国以后的郡县制

中国历史地方行政一向推崇汉朝,所谓两汉吏治。

秦始皇统一天下后,曾出现过应否置郡的争论。当时不少大臣都主张实行分封,授各地贵族予世袭的诸侯名分,惟身为廷尉的李斯却力排众议实行郡县制,并得到秦始皇的采纳。在郡县制底下,共设三十六郡(后增至四十一郡),每郡有守(相当于省长)、尉(相当于防区司令)和监(相当于监察专员)各一。郡下辖县;郡(守)与县(令),由皇帝直接任命。

汉代承袭这个制度。西汉建立之初,但也分封了一些诸侯国,郡县制与分封制并行,所以又称为郡国制。吴、楚七国之乱后诸侯国的权力被极大削弱,郡县制成为主体。大体汉代有一百多个郡,以一个郡有十多个县计,县总数有一千一百到一千四百多个。汉代郡长官为太守,秩二千石。和当时九卿秩中二千石,地位大致平等。汉代郡太守表现的好,可以调到中央朝廷可以做九卿(类似今日各部的部长),算是升级,但名义上好像差别不大(名义上都是二千石的官);若九卿再晋升,就是三公,是万石。九卿,也可以外调出来也做郡太守或国相,这一定程度而言也算是降调,但级别落差不像唐朝的六部尚书被流放到地方上的州刺史,两者职等差别那么大。而汉朝时代,尽管中央政府大一统,地方行政区域划分得小,当时郡太守名位和九卿,比起唐代是较为相近的。

当然历史发展的过程总会经历太多的变迁。郡县制度也逐渐在发展并部分废弃。

秦始皇消灭六国统一天下,六国人民并不心服,各地都有驻留兵力的必要,所以分天下为三十六郡,郡下统县,成为中国第一个统一王朝的郡县二级行政区划设置。西汉由于恢复了一定程度的分封制,所以郡的同级还出现了诸侯王国,以郡、国统县,仍然是二级制。郡的数量也大大增加,由秦末的约48郡,增加到了汉朝的约102郡。

东汉末年三国时期,原来只起监察作用的13个州成为正式的一级行政区,郡成为州以下的二级行政区。此后,历经三国、东晋、南北朝等分裂割据局面,由于大量增分建制,州郡县三级行政区划体系发生重大转变。最后全国出现了200多个州、600多个郡、1000多个县,一州只有两三个郡、一郡只有两三个县,介于州县之间的郡的实际意义几乎不复存在。

隋文帝在中国统一后,废除了天下各郡,实行州县二级制。不久后,隋炀帝又改州为郡,恢复到了秦汉的郡县二级制。唐朝建立后,再次改郡为州,但到了唐玄宗时又改州为郡,这也是郡最后一次作为正式行政区划出现。到了唐玄宗禅让,唐肃宗登基后,再次改郡为州,从此中国不再使用郡的划分。但宋朝的州则有一个郡名作别名,后来的大理国和太平天国等政权亦设置过郡。

 

隋废郡,以州领县,太守之官遂废,以州刺史取代郡守一职。此后太守不再是正式官名,仅用作刺史或知府的别称。宋代以后,时雅称知府、知州等官为太守。如〈醉翁亭记〉:“太守谓谁?庐陵欧阳修也。”

 

郡/州这一级行政长官称谓:郡守-太守-州刺史/刺史-知府/知州

注意:东汉某年的州刺史和后世隋文帝、唐代的州刺史实际意义不一样;前者是州-郡-县三级,后者是州-县二级

 

References:

https://zh.wikipedia.org/wiki/郡县制

https://zh.wikipedia.org/wiki/郡

https://zh.wikipedia.org/wiki/太守

https://zh.wikipedia.org/wiki/刺史

 

汉之十三州

   十三州,西汉时期的十三刺史部,汉武帝设置,其中十一州的名字沿用了《书经·禹贡》、《周礼·职方》的州名,所以俗称十三州。

汉成帝绥和元年(前8年),刺史改为州牧,州成为正式名称。后来又改回刺史,东汉末年,刺史的辖境不再称部,专称州。

  • 西汉十三州:朔方刺史部、兖州刺史部、青州刺史部、豫州刺史部、徐州刺史部、冀州刺史部、幽州刺史部、并州刺史部、扬州刺史部、荆州刺史部、益州刺史部、凉州刺史部、交趾刺史部。
  • 东汉十三州:司隶校尉部、兖州刺史部、青州刺史部、豫州刺史部、徐州刺史部、冀州刺史部、幽州刺史部、并州刺史部、扬州刺史部、荆州刺史部、益州刺史部、凉州刺史部、交州刺史部。

那么问题来了,州到底是一个什么样的机构了?

众所周知,秦并六国后,建立了郡县二级政权的地方行政制度,代替了之前周朝的封建制度(分封制)。后来汉朝设置了州(刺史部)这一级机构,但是起初的州是一个监察机构,其官吏称之为州刺史。

   州在东汉并不是一级行政区划。直到汉灵帝中平五年(188年),州刺史仍然只是没有固定治所的高级监察官吏,而且最初品秩只有六百石,甚至不如县令。但到了黄巾之乱后,汉灵帝为了镇压各地黄巾军余部及其它叛乱力量,将部分刺史升为州牧,而且刺史与州牧被授权统一掌管一州实际军政大权,最终促成了天下分裂的局面和三国时代的出现。州牧与刺史因此成为东汉晚期第一级地方行政长官,权位在太守之上,而刺史有功往往可以晋升州牧。

也就是说,到了汉灵帝时期,就有了“州-郡-县”和“郡-县”并存的局面,这部分升级的州就是实打实的行政机构了(其实是军政都抓)。

东汉行政区划(图): https://zh.wikipedia.org/wiki/东汉行政区划#/media/File:China_Han_Dynasty_2.jpg

References:

https://zh.wikipedia.org/wiki/十三州_(汉朝)

https://zh.wikipedia.org/wiki/东汉行政区划

grep不显示自己

最后更新时间:2022-05-31

要想在使用grep时不显示自己,常规有下面两种做法

ps -ef | grep "nginx"|grep -v "grep"

ps -ef | grep "[n]ginx"

grep -v 过滤grep自身可以通过man获取帮助。但是grep “[n]ginx”是如何实现不显示grep本身的了?

寻思很久,终于在stackoverflow上看到了一个醍醐灌顶的答案。

ps -ef | grep “[n]ginx” 命令中,grep 命令的参数是“[n]ginx”,正则[n]ginx当然不能匹配它!
ps -ef | grep "[n]ginx" 命令中,grep 命令的参数是正则表达式"[n]ginx",正则表达式"[n]ginx"可以匹配文本"nginx",但是不能匹配"[n]ginx"啊。

PS:我们使用grep时,也可能这样写ps -ef | grep [n]ginx (即grep的参数不带引号),虽然也是能工作,但是man文档建议大家还是要用引号包裹参数。

man grep:

grep searches for PATTERNS in each FILE. PATTERNS is one or more patterns separated by newline characters, and grep prints each line that matches a pattern. Typically PATTERNS should be
quoted when grep is used in a shell command.