在windows的cmd模式,使用ftp指令無法下載。
決定使用winscp來取代。
建立參數檔:script.txt
option batch abort
option confirm off
option transfer binary
open ftp://LoginID:LogPwd@FTP_Host
put d:\examplefile.txt
close
exit
建立執行檔:ftp.bat
winscp.com /script=\script.txt /ini=nul /log=\session.log
將ftp.bat、script.txt放在winscp資料夾
執行ftp.bat即可。也可寫入排程固定執行。
使用sftp
sftp://LoginID:LogPwd@FTP_Host -hostkey="ssh-rsa 1024 XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:X:XX:XX:XX:XX"
使用scp
winscp.exe scp://test@example.com:2222 /privatekey=mykey.ppk
使用ftps
winscp.exe ftps://martin@example.com /implicit /certificate="xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
參考資料:
SFTP使用WinSCP
Useful Scripts
Scripting and Task Automation
Example
In the example below, WinSCP connects to example.com server with account user, downloads file and closes the session. Then it connects to the same server with the account user2 and uploads the file back.
# Connect
open sftp://user:password@example.com/ -hostkey="ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
# Change remote directory
cd /home/user
# Force binary mode transfer
option transfer binary
# Download file to the local directory d:\
get examplefile.txt d:\
# Disconnect
close
# Connect as a different user
open sftp://user2:password@example.com/
# Change the remote directory
cd /home/user2
# Upload the file to current working directory
put d:\examplefile.txt
# Disconnect
close
# Exit WinSCP
exit
Save the script to the file example.txt. To execute the script file use the following command.
winscp.com /ini=nul /script=example.txt
==
For simple scripts you can specify all the commands on command-line using /command switch:
winscp.com /ini=nul /command "open sftp://user:password@example.com/ -hostkey=""ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx""" "get examplefile.txt d:\" "exit"
==
In Windows batch file, you can use ^ to split too long command-line to separate lines by escaping following new-line character:
winscp.com /ini=nul /command ^
"open sftp://user:password@example.com/ -hostkey=""ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx""" ^
"get examplefile.txt d:\" ^
"exit"
See other useful example scripts.
2016年11月22日 星期二
2016年11月18日 星期五
電腦 nginx增加ssl功能
增加ssl
nginx.conf
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}
測試ssl
openssl s_client -connect www.example.com:443
worker_processes auto;
nginx.conf
http {
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen 443 ssl;
server_name www.example.com;
keepalive_timeout 70;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
or
nginx.conf
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}
測試ssl
openssl s_client -connect www.example.com:443
==HTTPS server optimization
worker_processes auto;
nginx.conf
http {
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen 443 ssl;
server_name www.example.com;
keepalive_timeout 70;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
==Name-based HTTPS servers
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
or
server { listen 192.168.1.1:443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 192.168.1.2:443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... }
==
An SSL certificate with several names
ssl_certificate common.crt; ssl_certificate_key common.key; server { listen 443 ssl; server_name www.example.com; ... } server { listen 443 ssl; server_name www.example.org; ... }
Configuring HTTPS servers
電腦 Linux-將IIS的SSL憑證移至Centos使用
將IIS 匯出的 PKCS12 憑證檔 (mycert.pfx) 轉換
openssl pkcs12 -in mycert.pfx -out mycert.txt -nodes
輸入憑證密碼,建立 mycert.txt 檔案
mycert.txt 檔案,裡面同時包含兩個憑證,分別是 伺服器私鑰(RSA PRIVATE KEY) 與 伺服器憑證(CERTIFICATE)
將mycert.txt中包含
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
複製到server.key
將mycert.txt中包含
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
複製到server.crt
就可以將server.key、server.crt導入到網站(apache、nginx)使用
將 IIS 中已安裝的 SSL 憑證移至 Apache 2.2 for Win32 安裝
2016年11月17日 星期四
電腦 CentOS yum server 建置-對外更新
Yum Server 建置-對外更新
新增硬碟(40G)為/data,放置更新檔。
建立更新目錄
mkdir -p /data/centos/7
安裝相關更新套件
yum install yum-utils createrepo
下載套件
cd /data/centos/7
reposync --repoid=updates --repoid=extras --repoid=base
建立索引檔
createrepo /data/centos/7/base/
createrepo /data/centos/7/extras/
createrepo /data/centos/7/updates/
建立網站服務,讓client更新
使用httpd
yum install httpd
systemctl start httpd
systemctl enable httpd
建立更新目錄連結
mkdir -p /var/www/html/centos/7/updates /var/www/html/centos/7/extras/ /var/www/html/centos/7/base/
cd /var/www/html/centos/7/updates && ln -s /data/centos/7/updates/ x86_64 && cd -
cd /var/www/html/centos/7/extras && ln -s /data/centos/7/extras/ x86_64 && cd -
cd /var/www/html/centos/7/base && ln -s /data/centos/7/base/ x86_64 && cd -
建立更新repo
vim /etc/yum.repos.d/local.repo
[local-base]
name=Local Server-base
baseurl=http://192.168.1.72/centos/7/base/x86_64
enabled=1
[local-extras]
name=Local Server-extras
baseurl=http://192.168.1.72/centos/7/extras/x86_64
enabled=1
[local-updates]
name=Local Server-updates
baseurl=http://192.168.1.72/centos/7/updates/x86_64
enabled=1
指定由local更新
yum update --disablerepo="*" --enablerepo="local*"
每月定期更新排程
vi /etc/cron.monthly/repoupdate.sh
#!/bin/sh
cd /data/centos/7
reposync --repoid=updates --repoid=extras --repoid=base
createrepo /data/centos/7/base/
createrepo /data/centos/7/extras/
createrepo /data/centos/7/updates/
chomd +x /etc/cron.monthly/repoupdate.sh
2016年11月16日 星期三
電腦 CentOS yum server建置-使用iso檔
Yum Server建置-使用iso檔
本機
1.掛載iso檔
a.在vmware環境下,光碟機先掛載iso檔,不用上傳至主機。
ls -l /dev/cdrom
mount /dev/cdrom /mnt
mount /dev/cdrom /mnt
b.直接上傳iso檔至主機,將iso檔掛載至/mnt。
mount -o loop,ro CentOS-7-x86_64-Everything-1511.iso /mnt/cdrom
2.新增local.repo
vim /etc/yum.repos.d/local.repo
[local]
name=Local ISO
baseurl=file:///mnt/cdrom
gpgcheck=0
enabled=1
3.指定由local更新
yum update --disablerepo="*" --enablerepo="local"
指定由local安裝httpd
yum install --disablerepo="*" --enablerepo="local" httpd
其它主機可以經由http或ftp協定更新
a.使用httpd
yum install --disablerepo="*" --enablerepo="local" httpd
指定路徑
cd /var/www/html
ln -sf /mnt
啟用httpd
systemctl start httpd
systemctl enable httpd
b.使用vsftpd
yum install --disablerepo="*" --enablerepo="local" vsftpd
修改登匿名者登入目錄
echo 'anon_root=/mnt' >> /etc/vsftpd/vsftpd.conf
啟用httpd
systemctl start vsftpd
systemctl enable vsftpd
c.新增local.repo,看要http或ftp。
vim /etc/yum.repos.d/local.repo
[local]
name=Local ISO
baseurl=http://192.168.1.72/mnt
baseurl=ftp://192.168.1.72/
gpgcheck=0
enabled=1
3.指定由local更新
yum update --disablerepo="*" --enablerepo="local"
指定由local安裝httpd
yum install --disablerepo="*" --enablerepo="local" httpd
mount -o loop,ro CentOS-7-x86_64-Everything-1511.iso /mnt/cdrom
2.新增local.repo
vim /etc/yum.repos.d/local.repo
[local]
name=Local ISO
baseurl=file:///mnt/cdrom
gpgcheck=0
enabled=1
3.指定由local更新
yum update --disablerepo="*" --enablerepo="local"
指定由local安裝httpd
yum install --disablerepo="*" --enablerepo="local" httpd
其它主機可以經由http或ftp協定更新
a.使用httpd
yum install --disablerepo="*" --enablerepo="local" httpd
指定路徑
cd /var/www/html
ln -sf /mnt
啟用httpd
systemctl start httpd
systemctl enable httpd
b.使用vsftpd
yum install --disablerepo="*" --enablerepo="local" vsftpd
修改登匿名者登入目錄
echo 'anon_root=/mnt' >> /etc/vsftpd/vsftpd.conf
啟用httpd
systemctl start vsftpd
systemctl enable vsftpd
c.新增local.repo,看要http或ftp。
vim /etc/yum.repos.d/local.repo
[local]
name=Local ISO
baseurl=http://192.168.1.72/mnt
baseurl=ftp://192.168.1.72/
gpgcheck=0
enabled=1
3.指定由local更新
yum update --disablerepo="*" --enablerepo="local"
指定由local安裝httpd
yum install --disablerepo="*" --enablerepo="local" httpd
2016年11月14日 星期一
電腦 nginx增加modsecurity功能
modsecurity 安裝
wget https://www.modsecurity.org/tarball/2.9.1/modsecurity-2.9.1.tar.gz
tar -zxvf modsecurity-2.9.1.tar.gz
cd modsecurity-2.9.1
./configure --enable-standalone-module --disable-mlogc
make
nginx 安裝
wget http://nginx.org/download/nginx-1.10.2.tar.gz
tar -zxvf nginx-1.10.2.tar.gz
cd nginx-1.10.2
./configure --add-module=../modsecurity-2.9.1/nginx/modsecurity/
modsecurity設定
cp ../modsecurity-2.9.1/modsecurity.conf-recommended /etc/nginx/modsecurity.conf
cp ../modsecurity-2.9.1/unicode.mapping /etc/nginx/
vim nginx.conf
增加
ModSecurityEnabled on;
ModSecurityConfig modsecurity.conf;
測試
nginx -t
啟用nginx後,檢查error.log
增加 OWASP ModSecurity Core Rule Set (CRS) 規則
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git
or
wget https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/v3.0.0.tar.gz
tar zxvpf v3.0.0.tar.gz
mv owasp-modsecurity-crs-3.0.0/ /etc/nginx/owasp-modsecurity-crs
cp crs-setup.conf.example crs-setup.conf
cp rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
cp rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
新增 modsec_includes.conf
include modsecurity.conf
include owasp-modsecurity-crs/crs-setup.conf
如果需要其它規則也可以加入
include owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
修改nginx.conf
將
ModSecurityConfig modsecurity.conf;
更改為
ModSecurityConfig modsec_includes.conf;
重新載入nginx
Cross-site Scripting test request
http://192.168.1.106/search.aspx?txtSearch=%3Cscript%3Ealert%28%27foo%27%29%3C%2Fscript%3E
電腦 Windows Server試用序號
Windows Server試用序號
Windows Server 2008 R2 Web: KBV3Q-DJ8W7-VPB64-V88KG-82C49
Windows Server 2008 R2 Standard: 4GGC4-9947F-FWFP3-78P6F-J9HDR
Windows Server 2008 R2 Enterprise: 7PJBC-63K3J-62TTK-XF46D-W3WMD
Windows Server 2008 R2 Datacenter: QX7TD-2CMJR-D7WWY-KVCYC-6D2YT
Windows Server 2008 R2 Evaluation Product Keys
Windows Server 2012
D2N9P-3P6X9-2R39C-7RTCD-MDVJX
Windows Server 2012 R2 Evaluation Product Keys
到期後延長使用期限
Windows Server 2008 R2 SP1 評估版與延長使用期限
Windows Server 2008 R2 180天試用期延展
Windows Server 2008 R2 Web: KBV3Q-DJ8W7-VPB64-V88KG-82C49
Windows Server 2008 R2 Standard: 4GGC4-9947F-FWFP3-78P6F-J9HDR
Windows Server 2008 R2 Enterprise: 7PJBC-63K3J-62TTK-XF46D-W3WMD
Windows Server 2008 R2 Datacenter: QX7TD-2CMJR-D7WWY-KVCYC-6D2YT
Windows Server 2008 R2 Evaluation Product Keys
Windows Server 2012
D2N9P-3P6X9-2R39C-7RTCD-MDVJX
Windows Server 2012 R2 Evaluation Product Keys
到期後延長使用期限
Windows Server 2008 R2 SP1 評估版與延長使用期限
Windows Server 2008 R2 180天試用期延展
電腦 nginx的ngx_cache_purge功能
下載ngx_cache_purge
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
tar zxvf ./ngx_cache_purge-2.3.tar.gz
重新編譯,增加--add-module=../ngx_cache_purge-2.3 參數
make clean
./configure \
‧
--add-module=../ngx_cache_purge-2.3
make
make install
設定nginx.conf
vi /etc/nginx/nginx.conf
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key $uri$is_args$args;
proxy_cache_purge PURGE from 127.0.0.1;
}
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
tar zxvf ./ngx_cache_purge-2.3.tar.gz
重新編譯,增加--add-module=../ngx_cache_purge-2.3 參數
make clean
./configure \
‧
--add-module=../ngx_cache_purge-2.3
make
make install
設定nginx.conf
vi /etc/nginx/nginx.conf
proxy_cache_path /tmp/cache keys_zone=tmpcache:10m;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache tmpcache;
proxy_cache_key $uri$is_args$args;
proxy_cache_purge PURGE from 127.0.0.1;
}
CentOS-Nginx安裝-原始碼
1.Centos 7最小安裝
2.依據yum安裝的編譯設定
3.安裝相關rpm
yum groupinstall "Development Tools"
4.下載 nginx
5.安裝 nginScript(njs) dynamic module
curl -L -O http://hg.nginx.org/njs/archive/tip.tar.gz
wget http://hg.nginx.org/njs/archive/tip.tar.gz
tar zxvf ./tip.tar.gz
mv ./njs-91543c86f412 ./nginx-1.9.13
cd ./nginx-1.9.13/njs-91543c86f412
./configure
make
6. 安裝 module
yum install pcre-devel openssl-devel libxslt-devel gd-devel perl-ExtUtils-Embed http-devel GeoIP-devel
7.編譯
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-http_xslt_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_geoip_module=dynamic \
--with-http_perl_module=dynamic \
--with-threads \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-mail \
--with-mail_ssl_module \
--with-file-aio \
--with-ipv6 \
--with-http_v2_module \
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic' \
--with-ld-opt=-Wl,-E
make
make install
#NJS單獨可以編譯,未解決
--add-dynamic-module=njs-91543c86f412/nginx \
nginxのコンパイルメモ
2.依據yum安裝的編譯設定
3.安裝相關rpm
yum groupinstall "Development Tools"
4.下載 nginx
wget http://nginx.org/download/nginx-1.10.2.tar.gz
tar zxvpf nginx-1.10.2.tar.gz5.安裝 nginScript(njs) dynamic module
curl -L -O http://hg.nginx.org/njs/archive/tip.tar.gz
wget http://hg.nginx.org/njs/archive/tip.tar.gz
tar zxvf ./tip.tar.gz
mv ./njs-91543c86f412 ./nginx-1.9.13
cd ./nginx-1.9.13/njs-91543c86f412
./configure
make
6. 安裝 module
yum install pcre-devel openssl-devel libxslt-devel gd-devel perl-ExtUtils-Embed http-devel GeoIP-devel
7.編譯
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-http_xslt_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_geoip_module=dynamic \
--with-http_perl_module=dynamic \
--with-threads \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-mail \
--with-mail_ssl_module \
--with-file-aio \
--with-ipv6 \
--with-http_v2_module \
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic' \
--with-ld-opt=-Wl,-E
make
make install
#NJS單獨可以編譯,未解決
--add-dynamic-module=njs-91543c86f412/nginx \
nginxのコンパイルメモ
電腦 nginx的http_slice_module功能
確認nginx 是否有包含aio功能
nginx -v
是否有 --with-http_slice_module
如果沒有,需重新編譯
設定nginx.conf
vi /etc/nginx/nginx.conf
proxy_cache_path /tmp/nginx/cache levels=1:2 keys_zone=cache:100m;
location / {
slice 1m;
proxy_cache cache;
proxy_cache_key $uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_cache_valid 200 206 1h;
#proxy_set_header Range $http_range;
proxy_pass http://127.0.0.1:8080;
}
嚐鮮:Nginx-1.9.8推出的切片模塊
首先,如果不帶Range 請求,後端大文件在本地cache 時,會按照配置的slice 大小進行切片存儲。
其次,如果帶Range 請求,則Nginx 會用合適的Range 大小(以slice 為邊界)去後端請求,這個大小跟客戶端請求的Range 可能不一樣,並將以slice 為大小的切片存儲到本地,並以正確的206響應客戶端。
注意上面所說的,Nginx 到後端的Range 並不一定等於客戶端請求的Range,因為無論你請求的Range 如何,Nginx 到後端總是以slice 大小為邊界,將客戶端請求分割成若干個子請求到後端,假設配置的slice 大小為1M,即1024字節,那麼如果客戶端請求Range 為0-1023範圍以內任何數字,均會落到第一個切片上,如果請求的Range 橫跨了幾個slice 大小,則nginx會向後端發起多個子請求,將這幾個slice 緩存下來。而對客戶端,均以客戶端請求的Range 為準。如果一個請求中,有一部分文件之前沒有緩存下來,則Nginx 只會去向後端請求缺失的那些切片。
由於這個模塊是建立在子請求的基礎上,會有這麼一個潛在問題:當文件很大或者slice 很小的時候,會按照slice 大小分成很多個子請求,而這些個子請求並不會馬上釋放自己的資源,可能會導致文件描述符耗盡等情況。
需要注意的點:
1.該模塊用在proxy_cache 大文件的場景,將大文件切片緩存
2.編譯時對configure 加上--with-http_slice_module 參數
3.$slice_range 一定要加到proxy_cache_key 中,並使用proxy_set_header 將其作為Range 頭傳遞給後端
4.要根據文件大小合理設置slice 大小
Nginx:作為緩存,支持Range回源
電腦 nginx使用 aio 功能
確認nginx 是否有包含aio功能
nginx -v
是否有 --with-file-aio
如果沒有,需重新編譯
設定nginx.conf
vi /etc/nginx/nginx.conf
location / {
aio on;
directio 1;
output_buffers 1 128k;
}
Nginx 使用Linux-native aio 需要Linux 內核支持
Nginx 性能優異在於善於利用操作系統內核的各種特性,比如aio/epoll/sendfile (Linux), kqueue (FreeBSD) 等。對於使用VPS 做圖片站的站長來說,使用nginx 的aio 特性會大大提高性能,圖片站的特點是大量的讀io 操作,nginx aio 不用等待每次io 的結果有助於並發處理大量io 和提高nginx 處理效率。
nginx -v
是否有 --with-file-aio
如果沒有,需重新編譯
設定nginx.conf
vi /etc/nginx/nginx.conf
location / {
aio on;
directio 1;
output_buffers 1 128k;
}
Nginx 使用Linux-native aio 需要Linux 內核支持
Nginx 性能優異在於善於利用操作系統內核的各種特性,比如aio/epoll/sendfile (Linux), kqueue (FreeBSD) 等。對於使用VPS 做圖片站的站長來說,使用nginx 的aio 特性會大大提高性能,圖片站的特點是大量的讀io 操作,nginx aio 不用等待每次io 的結果有助於並發處理大量io 和提高nginx 處理效率。
2016年11月10日 星期四
電腦-(轉)CentOS 7 設定備註
CentOS 7 設定備註
環境是用最小安裝的
此最小安裝無法使用 ifconfig、route,不過可以用 ip addr,所以用 yum 安裝 net-tools
yum install net-tools
變更網卡名稱,centos7 在網卡上動了奇怪的手腳,名稱並不是 eth0
vi /etc/default/grub
在 GRUB_CMDLINE_LINUX 最後加上 net.ifnames=0 biosdevname=0
GRUB_CMDLINE_LINUX="xxxxxxxxxxx net.ifnames=0 biosdevname=0"
# 如果要顯示開機過程就拿掉 rhgb quiet
# 再執行 grub2-mkconfig 產生新的開機設定檔
grub2-mkconfig -o /boot/grub2/grub.cfg
# 就可以改網卡名稱為 eth0 了
mv /etc/sysconfig/network-scripts/ifcfg-enp0s3 /etc/sysconfig/network-scripts/ifcfg-eth0
vi /etc/sysconfig/network-scripts/ifcfg-eth0
NAME=eth0
centos7 的主機名稱則在 /etc/hostname 裡加入你所要的名稱即可
停用 NetworkManager (看樣子大家也都不喜歡它)
systemctl stop NetworkManager
systemctl disable NetworkManager
service network restart
or
systemctl restart network
停用 IPV6
vi /etc/default/grub 在 GRUB_CMDLINE_LINUX 最前面加入
ipv6.disable=1
每改一次 grub 就要 grub2-mkconfig -o /boot/grub2/grub.cfg
停用 firewalld, 改用 iptabless
systemctl stop firewalld
systemctl disable firewalld
yum install iptables-services
systemctl start iptables
systemctl enable iptables
rc.local 加上 x
chmod +x /etc/rc.d/rc.local
縮短開始 menu 的倒數時間
vi /etc/default/grub
GRUB_TIMEOUT=2
grub2-mkconfig -o /boot/grub2/grub.cfg
環境是用最小安裝的
此最小安裝無法使用 ifconfig、route,不過可以用 ip addr,所以用 yum 安裝 net-tools
yum install net-tools
變更網卡名稱,centos7 在網卡上動了奇怪的手腳,名稱並不是 eth0
vi /etc/default/grub
在 GRUB_CMDLINE_LINUX 最後加上 net.ifnames=0 biosdevname=0
GRUB_CMDLINE_LINUX="xxxxxxxxxxx net.ifnames=0 biosdevname=0"
# 如果要顯示開機過程就拿掉 rhgb quiet
# 再執行 grub2-mkconfig 產生新的開機設定檔
grub2-mkconfig -o /boot/grub2/grub.cfg
# 就可以改網卡名稱為 eth0 了
mv /etc/sysconfig/network-scripts/ifcfg-enp0s3 /etc/sysconfig/network-scripts/ifcfg-eth0
vi /etc/sysconfig/network-scripts/ifcfg-eth0
NAME=eth0
centos7 的主機名稱則在 /etc/hostname 裡加入你所要的名稱即可
停用 NetworkManager (看樣子大家也都不喜歡它)
systemctl stop NetworkManager
systemctl disable NetworkManager
service network restart
or
systemctl restart network
停用 IPV6
vi /etc/default/grub 在 GRUB_CMDLINE_LINUX 最前面加入
ipv6.disable=1
每改一次 grub 就要 grub2-mkconfig -o /boot/grub2/grub.cfg
停用 firewalld, 改用 iptabless
systemctl stop firewalld
systemctl disable firewalld
yum install iptables-services
systemctl start iptables
systemctl enable iptables
rc.local 加上 x
chmod +x /etc/rc.d/rc.local
縮短開始 menu 的倒數時間
vi /etc/default/grub
GRUB_TIMEOUT=2
grub2-mkconfig -o /boot/grub2/grub.cfg
電腦-(轉)優化Linux的內核參數來提高服務器並發處理能力
優化Linux的內核參數來提高服務器並發處理能力
PS:在服務器硬件資源額定有限的情況下,最大的壓榨服務器的性能,提高服務器的並發處理能力,是很多運維技術人員思考的問題。要提高Linux系統下的負載能力,可以使用nginx等原生並發處理能力就很強的web服務器,如果使用Apache的可以啟用其Worker模式,來提高其並發處理能力。除此之外,在考慮節省成本的情況下,可以修改Linux的內核相關TCP參數,來最大的提高服務器性能。當然,最基礎的提高負載問題,還是升級服務器硬件了,這是最根本的。
Linux系統下,TCP連接斷開後,會以TIME_WAIT狀態保留一定的時間,然後才會釋放端口。當並發請求過多的時候,就會產生大量的TIME_WAIT狀態的連接,無法及時斷開的話,會佔用大量的端口資源和服務器資源。這個時候我們可以優化TCP的內核參數,來及時將TIME_WAIT狀態的端口清理掉。
本文介紹的方法只對擁有大量TIME_WAIT狀態的連接導致系統資源消耗有效,如果不是這種情況下,效果可能不明顯。可以使用netstat命令去查TIME_WAIT狀態的連接狀態,輸入下面的組合命令,查看當前TCP連接的狀態和對應的連接數量:
#netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
這個命令會輸出類似下面的結果: 我們只用關心TIME_WAIT的個數,在這裡可以看到,有18000多個TIME_WAIT,這樣就佔用了18000多個端口。要知道端口的數量只有65535個,佔用一個少一個,會嚴重的影響到後繼的新連接。這種情況下,我們就有必要調整下Linux的TCP內核參數,讓系統更快的釋放TIME_WAIT連接。
LAST_ACK 16
SYN_RECV 348
ESTABLISHED 70
FIN_WAIT1 229
FIN_WAIT2 30
CLOSING 33
TIME_WAIT 18098
用vim打開配置文件:#vim /etc/sysctl.conf
在這個文件中,加入下面的幾行內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
輸入下面的命令,讓內核參數生效:#sysctl -p
簡單的說明上面的參數的含義:
net.ipv4.tcp_syncookies = 1
#表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉;
net.ipv4.tcp_tw_reuse = 1
#表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;
net.ipv4.tcp_tw_recycle = 1
#表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉;
net .ipv4.tcp_fin_timeout
#修改系統默認的TIMEOUT時間。
在經過這樣的調整之後,除了會進一步提升服務器的負載能力之外,還能夠防禦小流量程度的DoS、CC和SYN攻擊。
此外,如果你的連接數本身就很多,我們可以再優化一下TCP的可使用端口範圍,進一步提升服務器的並發能力。依然是往上面的參數文件中,加入下面這些配置: #這幾個參數,建議只在流量非常大的服務器上開啟,會有顯著的效果。一般的流量小的服務器上,沒有必要去設置這幾個參數。
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_keepalive_time = 1200
#表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,改為20分鐘。
net.ipv4.ip_local_port_range = 10000 65000
#表示用於向外連接的端口範圍。缺省情況下很小:32768到61000,改為10000到65000。(注意:這裡不要將最低值設的太低,否則可能會佔用掉正常的端口!)
net.ipv4.tcp_max_syn_backlog = 8192
#表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數。
net.ipv4.tcp_max_tw_buckets = 6000
#表示系統同時保持TIME_WAIT的最大數量,如果超過這個數字,TIME_WAIT將立刻被清除並打印警告信息。默認為180000,改為6000。對於Apache、Nginx等服務器,上幾行的參數可以很好地減少TIME_WAIT套接字數量,但是對於Squid,效果卻不大。此項參數可以控制TIME_WAIT的最大數量,避免Squid服務器被大量的TIME_WAIT拖死。
內核其他TCP參數說明:
net.ipv4.tcp_max_syn_backlog = 65536
#記錄的那些尚未收到客戶端確認信息的連接請求的最大值。對於有128M內存的系統而言,缺省值是1024,小內存的系統則是128。
net.core.netdev_max_backlog = 32768
#每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目。
net.core.somaxconn = 32768
#web應用中listen函數的backlog默認會給我們內核參數的net.core.somaxconn限製到128,而nginx定義的NGX_LISTEN_BACKLOG默認為511,所以有必要調整這個值。
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216 #最大socket讀buffer,可參考的優化值:873200
net.core.wmem_max = 16777216 #最大socket寫buffer,可參考的優化值:873200
net.ipv4.tcp_timestsmps = 0
#時間戳可以避免序列號的捲繞。一個1Gbps的鏈路肯定會遇到以前用過的序列號。時間戳能夠讓內核接受這種“異常”的數據包。這裡需要將其關掉。
net.ipv4.tcp_synack_retries = 2
#為了打開對端的連接,內核需要發送一個SYN並附帶一個回應前面一個SYN的ACK。也就是所謂三次握手中的第二次握手。這個設置決定了內核放棄連接之前發送SYN+ACK包的數量。
net.ipv4.tcp_syn_retries = 2
#在內核放棄建立連接之前發送SYN包的數量。
#net.ipv4.tcp_tw_len = 1
net.ipv4.tcp_tw_reuse = 1
#開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接。
net.ipv4.tcp_wmem = 8192 436600 873200
# TCP寫buffer,可參考的優化值: 8192 436600 873200
net.ipv4.tcp_rmem = 32768 436600 873200
# TCP讀buffer,可參考的優化值: 32768 436600 873200
net.ipv4. tcp_mem = 94500000 91500000 92700000
#同樣有3個值,意思是:
net.ipv4.tcp_mem[0]:低於此值,TCP沒有內存壓力。
net.ipv4.tcp_mem[1]:在此值下,進入內存壓力階段。
net.ipv4.tcp_mem[2]:高於此值,TCP拒絕分配socket。
上述內存單位是頁,而不是字節。可參考的優化值是:786432 1048576 1572864
net.ipv4.tcp_max_orphans = 3276800
#系統中最多有多少個TCP套接字不被關聯到任何一個用戶文件句柄上。
如果超過這個數字,連接將即刻被復位並打印出警告信息。
這個限制僅僅是為了防止簡單的DoS攻擊,不能過分依靠它或者人為地減小這個值,
更應該增加這個值(如果增加了內存之後)。
net.ipv4.tcp_fin_timeout = 30
#如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2狀態的時間。對端可以出錯並永遠不關閉連接,甚至意外當機。缺省值是60秒。2.2內核的通常值是180秒,你可以按這個設置,但要記住的是,即使你的機器是一個輕載的WEB服務器,也有因為大量的死套接字而內存溢出的風險,FIN- WAIT-2的危險性比FIN-WAIT-1要小,因為它最多只能吃掉1.5K內存,但是它們的生存期長些。
經過這樣的優化配置之後,你的服務器的TCP並發處理能力會顯著提高。以上配置僅供參考,用於生產環境請根據自己的實際情況。
PS:在服務器硬件資源額定有限的情況下,最大的壓榨服務器的性能,提高服務器的並發處理能力,是很多運維技術人員思考的問題。要提高Linux系統下的負載能力,可以使用nginx等原生並發處理能力就很強的web服務器,如果使用Apache的可以啟用其Worker模式,來提高其並發處理能力。除此之外,在考慮節省成本的情況下,可以修改Linux的內核相關TCP參數,來最大的提高服務器性能。當然,最基礎的提高負載問題,還是升級服務器硬件了,這是最根本的。
Linux系統下,TCP連接斷開後,會以TIME_WAIT狀態保留一定的時間,然後才會釋放端口。當並發請求過多的時候,就會產生大量的TIME_WAIT狀態的連接,無法及時斷開的話,會佔用大量的端口資源和服務器資源。這個時候我們可以優化TCP的內核參數,來及時將TIME_WAIT狀態的端口清理掉。
本文介紹的方法只對擁有大量TIME_WAIT狀態的連接導致系統資源消耗有效,如果不是這種情況下,效果可能不明顯。可以使用netstat命令去查TIME_WAIT狀態的連接狀態,輸入下面的組合命令,查看當前TCP連接的狀態和對應的連接數量:
#netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
這個命令會輸出類似下面的結果: 我們只用關心TIME_WAIT的個數,在這裡可以看到,有18000多個TIME_WAIT,這樣就佔用了18000多個端口。要知道端口的數量只有65535個,佔用一個少一個,會嚴重的影響到後繼的新連接。這種情況下,我們就有必要調整下Linux的TCP內核參數,讓系統更快的釋放TIME_WAIT連接。
LAST_ACK 16
SYN_RECV 348
ESTABLISHED 70
FIN_WAIT1 229
FIN_WAIT2 30
CLOSING 33
TIME_WAIT 18098
用vim打開配置文件:#vim /etc/sysctl.conf
在這個文件中,加入下面的幾行內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
輸入下面的命令,讓內核參數生效:#sysctl -p
簡單的說明上面的參數的含義:
net.ipv4.tcp_syncookies = 1
#表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉;
net.ipv4.tcp_tw_reuse = 1
#表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;
net.ipv4.tcp_tw_recycle = 1
#表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉;
net .ipv4.tcp_fin_timeout
#修改系統默認的TIMEOUT時間。
在經過這樣的調整之後,除了會進一步提升服務器的負載能力之外,還能夠防禦小流量程度的DoS、CC和SYN攻擊。
此外,如果你的連接數本身就很多,我們可以再優化一下TCP的可使用端口範圍,進一步提升服務器的並發能力。依然是往上面的參數文件中,加入下面這些配置: #這幾個參數,建議只在流量非常大的服務器上開啟,會有顯著的效果。一般的流量小的服務器上,沒有必要去設置這幾個參數。
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_keepalive_time = 1200
#表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,改為20分鐘。
net.ipv4.ip_local_port_range = 10000 65000
#表示用於向外連接的端口範圍。缺省情況下很小:32768到61000,改為10000到65000。(注意:這裡不要將最低值設的太低,否則可能會佔用掉正常的端口!)
net.ipv4.tcp_max_syn_backlog = 8192
#表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數。
net.ipv4.tcp_max_tw_buckets = 6000
#表示系統同時保持TIME_WAIT的最大數量,如果超過這個數字,TIME_WAIT將立刻被清除並打印警告信息。默認為180000,改為6000。對於Apache、Nginx等服務器,上幾行的參數可以很好地減少TIME_WAIT套接字數量,但是對於Squid,效果卻不大。此項參數可以控制TIME_WAIT的最大數量,避免Squid服務器被大量的TIME_WAIT拖死。
內核其他TCP參數說明:
net.ipv4.tcp_max_syn_backlog = 65536
#記錄的那些尚未收到客戶端確認信息的連接請求的最大值。對於有128M內存的系統而言,缺省值是1024,小內存的系統則是128。
net.core.netdev_max_backlog = 32768
#每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目。
net.core.somaxconn = 32768
#web應用中listen函數的backlog默認會給我們內核參數的net.core.somaxconn限製到128,而nginx定義的NGX_LISTEN_BACKLOG默認為511,所以有必要調整這個值。
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216 #最大socket讀buffer,可參考的優化值:873200
net.core.wmem_max = 16777216 #最大socket寫buffer,可參考的優化值:873200
net.ipv4.tcp_timestsmps = 0
#時間戳可以避免序列號的捲繞。一個1Gbps的鏈路肯定會遇到以前用過的序列號。時間戳能夠讓內核接受這種“異常”的數據包。這裡需要將其關掉。
net.ipv4.tcp_synack_retries = 2
#為了打開對端的連接,內核需要發送一個SYN並附帶一個回應前面一個SYN的ACK。也就是所謂三次握手中的第二次握手。這個設置決定了內核放棄連接之前發送SYN+ACK包的數量。
net.ipv4.tcp_syn_retries = 2
#在內核放棄建立連接之前發送SYN包的數量。
#net.ipv4.tcp_tw_len = 1
net.ipv4.tcp_tw_reuse = 1
#開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接。
net.ipv4.tcp_wmem = 8192 436600 873200
# TCP寫buffer,可參考的優化值: 8192 436600 873200
net.ipv4.tcp_rmem = 32768 436600 873200
# TCP讀buffer,可參考的優化值: 32768 436600 873200
net.ipv4. tcp_mem = 94500000 91500000 92700000
#同樣有3個值,意思是:
net.ipv4.tcp_mem[0]:低於此值,TCP沒有內存壓力。
net.ipv4.tcp_mem[1]:在此值下,進入內存壓力階段。
net.ipv4.tcp_mem[2]:高於此值,TCP拒絕分配socket。
上述內存單位是頁,而不是字節。可參考的優化值是:786432 1048576 1572864
net.ipv4.tcp_max_orphans = 3276800
#系統中最多有多少個TCP套接字不被關聯到任何一個用戶文件句柄上。
如果超過這個數字,連接將即刻被復位並打印出警告信息。
這個限制僅僅是為了防止簡單的DoS攻擊,不能過分依靠它或者人為地減小這個值,
更應該增加這個值(如果增加了內存之後)。
net.ipv4.tcp_fin_timeout = 30
#如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2狀態的時間。對端可以出錯並永遠不關閉連接,甚至意外當機。缺省值是60秒。2.2內核的通常值是180秒,你可以按這個設置,但要記住的是,即使你的機器是一個輕載的WEB服務器,也有因為大量的死套接字而內存溢出的風險,FIN- WAIT-2的危險性比FIN-WAIT-1要小,因為它最多只能吃掉1.5K內存,但是它們的生存期長些。
經過這樣的優化配置之後,你的服務器的TCP並發處理能力會顯著提高。以上配置僅供參考,用於生產環境請根據自己的實際情況。
電腦 Centos-firewalld設定-01
顯示目前的區域
firewall-cmd --get-default-zone
顯示啟動的區域
firewall-cmd --get-active-zones
更換區域連接網卡
firewall-cmd --zone=public --change-interface=ens160
顯示可掛載的服務
firewall-cmd --get-services
顯示目前的設定
firewall-cmd --list-all
關掉 DHCP 服務 port
sudo firewall-cmd --zone=public --remove-service dhcpv6-client
暫時開啟 DNS service
firewall-cmd --add-service=dns
firewall-cmd --list-all
永久開啟 DNS service
firewall-cmd --add-service=dns --permanent
firewall-cmd --reload
自行指定的連接埠
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all
顯示啟動的連接埠
firewall-cmd --list-ports
CentOS 7 Firewalld 防火牆說明介紹
CentOS 7 - firewalld防火牆基本概念
[CentOS 7] 防火牆設定
How To Set Up a Firewall Using FirewallD on CentOS 7
RHEL7: How to get started with Firewalld.
How to Configure ‘FirewallD’ in RHEL/CentOS 7 and Fedora 21
2016年11月9日 星期三
電腦 Linux-tcpdump 的用法
tcpdump 用法
tcpdump -i ens160 'tcp'
tcpdump -i ens160 'host 192.168.1.1'
tcpdump -i ens160 'tcp and host 192.168.1.1'
tcpdump -i ens160 'tcp port 22 and host 192.168.1.1'
tcpdump -i ens160 'tcp and (not port 22) and (net 192.168.1.0/24)'
tcpdump -i ens160 'udp port 161 and host 192.168.1.1'
如果條件很多的話,要在條件之前加 and 或 or 或 not
tcpdump -i eth0 host ! 211.161.223.70 and ! 211.161.223.71 and dst port 80
tcpdump 的用法
tcpdump -i ens160 'tcp'
tcpdump -i ens160 'host 192.168.1.1'
tcpdump -i ens160 'tcp and host 192.168.1.1'
tcpdump -i ens160 'tcp port 22 and host 192.168.1.1'
tcpdump -i ens160 'tcp and (not port 22) and (net 192.168.1.0/24)'
tcpdump -i ens160 'udp port 161 and host 192.168.1.1'
如果條件很多的話,要在條件之前加 and 或 or 或 not
tcpdump -i eth0 host ! 211.161.223.70 and ! 211.161.223.71 and dst port 80
tcpdump 的用法
電腦 Linux arping 指令
arping 網路測試指令
基本使用方式
# arping -I em1 -c 3 192.168.1.1
ARPING 192.168.1.1 from 192.168.1.10 em1
Unicast reply from 192.168.1.1 [00:50:7F:5A:3D:B8] 0.958ms
Sent 3 probes (1 broadcast(s))
Received 3 response(s)
-I 指定網卡
-c 發送封包次數
後面接對方IP Address
另外還有 -D 模式,用來偵測是否有重複的IP.
# arping -I em1 -D 192.168.1.1
ARPING 192.168.1.1 from 0.0.0.0 em1
Unicast reply from 192.168.1.1 [00:50:7F:5A:3D:B8] 0.772ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
# echo $?
1
若是return 為0代表有重複的IP.
還有一種情境如更換新的gateway,這時候雖然default gateway指向正確IP Address,
但是Mac Address是放在ARP Cache裡,並未更新,也會不通.此時可以利用arping來更新
ARP Cache.
#arping -q -c 3 -U -I em1 192.168.1.10
或是
#arping -q -c 3 -A -I em1 192.168.1.10
這裡要接自己的IP Address,這時候會廣播,gateway會回應,然後會更新ARP Cache.
基本使用方式
# arping -I em1 -c 3 192.168.1.1
ARPING 192.168.1.1 from 192.168.1.10 em1
Unicast reply from 192.168.1.1 [00:50:7F:5A:3D:B8] 0.958ms
Sent 3 probes (1 broadcast(s))
Received 3 response(s)
-I 指定網卡
-c 發送封包次數
後面接對方IP Address
另外還有 -D 模式,用來偵測是否有重複的IP.
# arping -I em1 -D 192.168.1.1
ARPING 192.168.1.1 from 0.0.0.0 em1
Unicast reply from 192.168.1.1 [00:50:7F:5A:3D:B8] 0.772ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
# echo $?
1
若是return 為0代表有重複的IP.
還有一種情境如更換新的gateway,這時候雖然default gateway指向正確IP Address,
但是Mac Address是放在ARP Cache裡,並未更新,也會不通.此時可以利用arping來更新
ARP Cache.
#arping -q -c 3 -U -I em1 192.168.1.10
或是
#arping -q -c 3 -A -I em1 192.168.1.10
這裡要接自己的IP Address,這時候會廣播,gateway會回應,然後會更新ARP Cache.
2016年11月7日 星期一
電腦 Linux-awk實用技巧-02
linux shell awk 語法
在命令行中輸入以下命令:
$ awk '{ print }' /etc/passwd
您將會見到 /etc/passwd 文件的內容出現在眼前。現在,解釋 awk 做了些什麼。調用 awk 時,我們指定 /etc/passwd 作為輸入文件。執行 awk 時,它依次對 /etc/passwd 中的每一行執行 print 命令。所有輸出都發送到 stdout,所得到的結果與與執行catting /etc/passwd完全相同。
現在,解釋 { print } 代碼塊。在 awk 中,花括號用於將幾塊代碼組合到一起,這一點類似於 C 語言。在代碼塊中只有一條 print 命令。在 awk 中,如果只出現 print 命令,那麼將打印當前行的全部內容。
這裡是另一個 awk 示例,它的作用與上例完全相同:
$ awk '{ print $0 }' /etc/passwd
在 awk 中,$0 變量表示整個當前行,所以 print 和 print $0 的作用完全一樣。
如果您願意,可以創建一個 awk 程序,讓它輸出與輸入數據完全無關的數據。以下是一個示例:
$ awk '{ print "" }' /etc/passwd
只要將 "" 字符串傳遞給 print 命令,它就會打印空白行。如果測試該腳本,將會發現對於 /etc/passwd 文件中的每一行,awk 都輸出一個空白行。再次說明, awk 對輸入文件中的每一行都執行這個腳本。以下是另一個示例:
$ awk '{ print "hiya" }' /etc/passwd
運行這個腳本將在您的屏幕上寫滿 hiya。
多個字段
awk 非常善於處理分成多個邏輯字段的文本,而且讓您可以毫不費力地引用 awk 腳本中每個獨立的字段。以下腳本將打印出您的系統上所有用戶帳戶的列表:
$ awk -F":" '{ print $1 }' /etc/passwd
上例中,在調用 awk 時,使用 -F 選項來指定 ":" 作為字段分隔符。awk 處理 print $1 命令時,它會打印出在輸入文件中每一行中出現的第一個字段。以下是另一個示例:
$ awk -F":" '{ print $1 $3 }' /etc/passwd
以下是該腳本輸出的摘錄:
halt7
operator11
root0
shutdown6
sync5
bin1
....etc.
如您所見,awk 打印出 /etc/passwd 文件的第一和第三個字段,它們正好分別是用戶名和用戶標識字段。現在,當腳本運行時,它並不理想 -- 在兩個輸出字段之間沒有空格!如果習慣於使用 bash 或 python 進行編程,那麼您會指望 print $1 $3 命令在兩個字段之間插入空格。然而,當兩個字符串在 awk 程序中彼此相鄰時,awk 會連接它們但不在它們之間添加空格。以下命令會在這兩個字段中插入空格:
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
以這種方式調用 print 時,它將連接 $1、" " 和 $3,創建可讀的輸出。當然,如果需要的話,我們還可以插入一些文本標籤:
$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
這將產生以下輸出:
username: halt uid:7
username: operator uid:11
username: root uid:0
username: shutdown uid:6
username: sync uid:5
username: bin uid:1
....etc.
外部腳本
將腳本作為命令行自變量傳遞給 awk 對於小的單行程序來說是非常簡單的,而對於多行程序,它就比較複雜。您肯定想要在外部文件中撰寫腳本。然後可以向 awk 傳遞 -f 選項,以向它提供此腳本文件:
$ awk -f myscript.awk myfile.in
將腳本放入文本文件還可以讓您使用附加 awk 功能。例如,這個多行腳本與前面的單行腳本的作用相同,它們都打印出 /etc/passwd 中每一行的第一個字段:
BEGIN {
FS=":"
}
{ print $1 }
這兩個方法的差別在於如何設置字段分隔符。在這個腳本中,字段分隔符在代碼自身中指定(通過設置 FS 變量),而在前一個示例中,通過在命令行上向 awk 傳遞 -F":" 選項來設置 FS。通常,最好在腳本自身中設置字段分隔符,只是因為這表示您可以少輸入一個命令行自變量。我們將在本文的後面詳細討論 FS 變量。
BEGIN 和 END 塊
通常,對於每個輸入行,awk 都會執行每個腳本代碼塊一次。然而,在許多編程情況中,可能需要在 awk 開始處理輸入文件中的文本之前執行初始化代碼。對於這種情況,awk 允許您定義一個 BEGIN 塊。我們在前一個示例中使用了 BEGIN 塊。因為 awk 在開始處理輸入文件之前會執行 BEGIN 塊,因此它是初始化 FS(字段分隔符)變量、打印頁眉或初始化其它在程序中以後會引用的全局變量的極佳位置。
awk 還提供了另一個特殊塊,叫作 END 塊。awk 在處理了輸入文件中的所有行之後執行這個塊。通常,END 塊用於執行最終計算或打印應該出現在輸出流結尾的摘要信息。
規則表達式和塊
awk 允許使用規則表達式,根據規則表達式是否匹配當前行來選擇執行獨立代碼塊。以下示例腳本只輸出包含字符序列 foo 的那些行:
/foo/ { print }
當然,可以使用更複雜的規則表達式。以下腳本將只打印包含浮點數的行:
/[0-9]+\.[0-9]*/ { print }
表達式和塊
還有許多其它方法可以選擇執行代碼塊。我們可以將任意一種布爾表達式放在一個代碼塊之前,以控制何時執行某特定塊。僅當對前面的布爾表達式求值為真時,awk 才執行代碼塊。以下示例腳本輸出將輸出其第一個字段等於 fred 的所有行中的第三個字段。如果當前行的第一個字段不等於 fred,awk 將繼續處理文件而不對當前行執行 print 語句:
$1 == "fred" { print $3 }
awk 提供了完整的比較運算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 還提供了 "~" 和 "!~" 運算符,它們分別表示「匹配」和「不匹配」。它們的用法是在運算符左邊指定變量,在右邊指定規則表達式。如果某一行的第五個字段包含字符序列 root,那麼以下示例將只打印這一行中的第三個字段:
$5 ~ /root/ { print $3 }
條件語句
awk 還提供了非常好的類似於 C 語言的 if 語句。如果您願意,可以使用 if 語句重寫前一個腳本:
{
if ( $5 ~ /root/ ) {
print $3
}
}
這兩個腳本的功能完全一樣。第一個示例中,布爾表達式放在代碼塊外面。而在第二個示例中,將對每一個輸入行執行代碼塊,而且我們使用 if 語句來選擇執行 print 命令。這兩個方法都可以使用,可以選擇最適合腳本其它部分的一種方法。
以下是更複雜的 awk if 語句示例。可以看到,儘管使用了複雜、嵌套的條件語句,if 語句看上去仍與相應的 C 語言 if 語句一樣:
{
if ( $1 == "foo" ) {
if ( $2 == "foo" ) {
print "uno"
} else {
print "one"
}
} else if ($1 == "bar" ) {
print "two"
} else {
print "three"
}
}
使用 if 語句還可以將代碼:
! /matchme/ { print $1 $3 $4 }
轉換成:
{
if ( $0 !~ /matchme/ ) {
print $1 $3 $4
}
}
這兩個腳本都只輸出不包含 matchme 字符序列的那些行。此外,還可以選擇最適合您的代碼的方法。它們的功能完全相同。
awk 還允許使用布爾運算符 "||"(邏輯與)和 "&&"(邏輯或),以便創建更複雜的布爾表達式:
( $1 == "foo" ) && ( $2 == "bar" ) { print }
這個示例只打印第一個字段等於 foo 且第二個字段等於 bar 的那些行。
數值變量!
至今,我們不是打印字符串、整行就是特定字段。然而,awk 還允許我們執行整數和浮點運算。通過使用數學表達式,可以很方便地編寫計算文件中空白行數量的腳本。以下就是這樣一個腳本:
BEGIN { x=0 }
/^$/ { x=x+1 }
END { print "I found " x " blank lines. " }
在 BEGIN 塊中,將整數變量 x 初始化成零。然後,awk 每次遇到空白行時,awk 將執行 x=x+1 語句,遞增 x。處理完所有行之後,執行 END 塊,awk 將打印出最終摘要,指出它找到的空白行數量。
字符串化變量
awk 的優點之一就是「簡單和字符串化」。我認為 awk 變量「字符串化」是因為所有 awk 變量在內部都是按字符串形式存儲的。同時,awk 變量是「簡單的」,因為可以對它執行數學操作,且只要變量包含有效數字字符串,awk 會自動處理字符串到數字的轉換步驟。要理解我的觀點,請研究以下這個示例:
x="1.01"
# We just set x to contain the *string* "1.01"
x=x+1
# We just added one to a *string*
print x
# Incidentally, these are comments
awk 將輸出:
2.01
有趣吧!雖然將字符串值 1.01 賦值給變量 x,我們仍然可以對它加一。但在 bash 和 python 中卻不能這樣做。首先,bash 不支持浮點運算。而且,如果 bash 有「字符串化」變量,它們並不「簡單」;要執行任何數學操作,bash 要求我們將數字放到醜陋的 $( ) ) 結構中。如果使用 python,則必須在對 1.01 字符串執行任何數學運算之前,將它轉換成浮點值。雖然這並不困難,但它仍是附加的步驟。如果使用 awk,它是全自動的,而那會使我們的代碼又好又整潔。如果想要對每個輸入行的第一個字段乘方並加一,可以使用以下腳本:
{ print ($1^2)+1 }
如果做一個小實驗,就可以發現如果某個特定變量不包含有效數字,awk 在對數學表達式求值時會將該變量當作數字零處理。
眾多運算符
awk 的另一個優點是它有完整的數學運算符集合。除了標準的加、減、乘、除,awk 還允許使用前面演示過的指數運算符 "^"、模(餘數)運算符 "%" 和其它許多從 C 語言中借入的易於使用的賦值操作符。
這些運算符包括前後加減(i++、--foo)、加/減/乘/除賦值運算符( a+=3、b*=2、c/=2.2、d-=6.2)。不僅如此 -- 我們還有易於使用的模/指數賦值運算符(a^=2、b%=4)。
字段分隔符
awk 有它自己的特殊變量集合。其中一些允許調整 awk 的運行方式,而其它變量可以被讀取以收集關於輸入的有用信息。我們已經接觸過這些特殊變量中的一個,FS。前面已經提到過,這個變量讓您可以設置 awk 要查找的字段之間的字符序列。我們使用 /etc/passwd 作為輸入時,將 FS 設置成 ":"。當這樣做有問題時,我們還可以更靈活地使用 FS。
FS 值並沒有被限制為單一字符;可以通過指定任意長度的字符模式,將它設置成規則表達式。如果正在處理由一個或多個 tab 分隔的字段,您可能希望按以下方式設置 FS:
FS="\t+"
以上示例中,我們使用特殊 "+" 規則表達式字符,它表示「一個或多個前一字符」。
如果字段由空格分隔(一個或多個空格或 tab),您可能想要將 FS 設置成以下規則表達式:
FS="[[:space:]+]"
這個賦值表達式也有問題,它並非必要。為什麼?因為缺省情況下,FS 設置成單一空格字符,awk 將這解釋成表示「一個或多個空格或 tab」。在這個特殊示例中,缺省 FS 設置恰恰是您最想要的!
複雜的規則表達式也不成問題。即使您的記錄由單詞 "foo" 分隔,後面跟著三個數字,以下規則表達式仍允許對數據進行正確的分析:
FS="foo[0-9][0-9][0-9]"
字段數量
接著我們要討論的兩個變量通常並不是需要賦值的,而是用來讀取以獲取關於輸入的有用信息。第一個是 NF 變量,也叫做「字段數量」變量。awk 會自動將該變量設置成當前記錄中的字段數量。可以使用 NF 變量來只顯示某些輸入行:
NF == 3 { print "this particular record has three fields: " $0 }
當然,也可以在條件語句中使用 NF 變量,如下:
{
if ( NF > 2 ) {
print $1 " " $2 ":" $3
}
}
記錄號
記錄號 (NR) 是另一個方便的變量。它始終包含當前記錄的編號(awk 將第一個記錄算作記錄號 1)。迄今為止,我們已經處理了每一行包含一個記錄的輸入文件。對於這些情況,NR 還會告訴您當前行號。然而,當我們在本系列以後部分中開始處理多行記錄時,就不會再有這種情況,所以要注意!可以像使用 NF 變量一樣使用 NR 來只打印某些輸入行:
(NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" }
另一個示例:
{
#skip header
if ( NR > 10 ) {
print "ok, now for the real information!"
}
}
AWK SHELL FOR LINUX
[ 2006-6-23 14:06:00 | By: nathena ]
多行記錄
awk 是一種用於讀取和處理結構化數據(如系統的 /etc/passwd 文件)的極佳工具。/etc/passwd 是 UNIX 用戶數據庫,並且是用冒號定界的文本文件,它包含許多重要信息,包括所有現有用戶帳戶和用戶標識,以及其它信息。在我的前一篇文章中,我演示了 awk 如何輕鬆地分析這個文件。我們只須將 FS(字段分隔符)變量設置成 ":"。
正確設置了 FS 變量之後,就可以將 awk 配置成分析幾乎任何類型的結構化數據,只要這些數據是每行一個記錄。然而,如果要分析佔據多行的記錄,僅僅依靠設置 FS 是不夠的。在這些情況下,我們還需要修改 RS 記錄分隔符變量。RS 變量告訴 awk 當前記錄什麼時候結束,新記錄什麼時候開始。
譬如,讓我們討論一下如何完成處理「聯邦證人保護計劃」所涉及人員的地址列表的任務:
Jimmy the Weasel
100 Pleasant Drive
San Francisco, CA 12345
Big Tony
200 Incognito Ave.
Suburbia, WA 67890
理論上,我們希望 awk 將每 3 行看作是一個獨立的記錄,而不是三個獨立的記錄。如果 awk 將地址的第一行看作是第一個字段 ($1),街道地址看作是第二個字段 ($2),城市、州和郵政編碼看作是第三個字段 $3,那麼這個代碼就會變得很簡單。以下就是我們想要得到的代碼:
BEGIN {
FS="\n"
RS=""
}
在上面這段代碼中,將 FS 設置成 "\n" 告訴 awk 每個字段都佔據一行。通過將 RS 設置成 "",還會告訴 awk 每個地址記錄都由空白行分隔。一旦 awk 知道是如何格式化輸入的,它就可以為我們執行所有分析工作,腳本的其餘部分很簡單。讓我們研究一個完整的腳本,它將分析這個地址列表,並將每個記錄打印在一行上,用逗號分隔每個字段。
address.awk
BEGIN {
FS="\n"
RS=""
}
{
print $1 ", " $2 ", " $3
}
如果這個腳本保存為 address.awk,地址數據存儲在文件 address.txt 中,可以通過輸入 "awk -f address.awk address.txt" 來執行這個腳本。此代碼將產生以下輸出:
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
OFS 和 ORS
在 address.awk 的 print 語句中,可以看到 awk 會連接(合併)一行中彼此相鄰的字符串。我們使用此功能在同一行上的三個字段之間插入一個逗號和空格 (", ")。這個方法雖然有用,但比較難看。與其在字段間插入 ", " 字符串,倒不如讓通過設置一個特殊 awk 變量 OFS,讓 awk 完成這件事。請參考下面這個代碼片斷。
print "Hello", "there", "Jim!"
這行代碼中的逗號並不是實際文字字符串的一部分。事實上,它們告訴 awk "Hello"、"there" 和 "Jim!" 是單獨的字段,並且應該在每個字符串之間打印 OFS 變量。缺省情況下,awk 產生以下輸出:
Hello there Jim!
這是缺省情況下的輸出結果,OFS 被設置成 " ",單個空格。不過,我們可以方便地重新定義 OFS,這樣 awk 將插入我們中意的字段分隔符。以下是原始 address.awk 程序的修訂版,它使用 OFS 來輸出那些中間的 ", " 字符串:
address.awk 的修訂版
BEGIN {
FS="\n"
RS=""
OFS=", "
}
{
print $1, $2, $3
}
awk 還有一個特殊變量 ORS,全稱是「輸出記錄分隔符」。通過設置缺省為換行 ("\n") 的 OFS,我們可以控制在 print 語句結尾自動打印的字符。缺省 ORS 值會使 awk 在新行中輸出每個新的 print 語句。如果想使輸出的間隔翻倍,可以將 ORS 設置成 "\n\n"。或者,如果想要用單個空格分隔記錄(而不換行),將 ORS 設置成 ""。
將多行轉換成用 tab 分隔的格式
假設我們編寫了一個腳本,它將地址列表轉換成每個記錄一行,且用 tab 定界的格式,以便導入電子錶格。使用稍加修改的 address.awk 之後,就可以清楚地看到這個程序只適合於三行的地址。如果 awk 遇到以下地址,將丟掉第四行,並且不打印該行:
Cousin Vinnie
Vinnie's Auto Shop
300 City Alley
Sosueme, OR 76543
要處理這種情況,代碼最好考慮每個字段的記錄數量,並依次打印每個記錄。現在,代碼只打印地址的前三個字段。以下就是我們想要的一些代碼:
適合具有任意多字段的地址的 address.awk 版本
BEGIN {
FS="\n"
RS=""
ORS=""
}
{
x=1
while ( x<NF ) {
print $x "\t"
x++
}
print $NF "\n"
}
首先,將字段分隔符 FS 設置成 "\n",將記錄分隔符 RS 設置成 "",這樣 awk 可以像以前一樣正確分析多行地址。然後,將輸出記錄分隔符 ORS 設置成 "",它將使 print 語句在每個調用結尾不輸出新行。這意味著如果希望任何文本從新的一行開始,那麼需要明確寫入 print "\n"。
在主代碼塊中,創建了一個變量 x 來存儲正在處理的當前字段的編號。起初,它被設置成 1。然後,我們使用 while 循環(一種 awk 循環結構,等同於 C 語言中的 while 循環),對於所有記錄(最後一個記錄除外)重複打印記錄和 tab 字符。最後,打印最後一個記錄和換行;此外,由於將 ORS 設置成 "",print 將不輸出換行。程序輸出如下,這正是我們所期望的:
我們想要的輸出。不算漂亮,但用 tab 定界,以便於導入電子錶格
Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345
Big Tony 200 Incognito Ave. Suburbia, WA 67890
Cousin Vinnie Vinnie's Auto Shop 300 City Alley Sosueme, OR 76543
循環結構
我們已經看到了 awk 的 while 循環結構,它等同於相應的 C 語言 while 循環。awk 還有 "do...while" 循環,它在代碼塊結尾處對條件求值,而不像標準 while 循環那樣在開始處求值。它類似於其它語言中的 "repeat...until" 循環。以下是一個示例:
do...while 示例
{
count=1
do {
print "I get printed at least once no matter what"
} while ( count != 1 )
}
與一般的 while 循環不同,由於在代碼塊之後對條件求值,"do...while" 循環永遠都至少執行一次。換句話說,當第一次遇到普通 while 循環時,如果條件為假,將永遠不執行該循環。
for 循環
awk 允許創建 for 循環,它就像 while 循環,也等同於 C 語言的 for 循環:
for ( initial assignment; comparison; increment ) {
code block
}
以下是一個簡短示例:
for ( x = 1; x <= 4; x++ ) {
print "iteration",x
}
此段代碼將打印:
iteration 1
iteration 2
iteration 3
iteration 4
break 和 continue
此外,如同 C 語言一樣,awk 提供了 break 和 continue 語句。使用這些語句可以更好地控制 awk 的循環結構。以下是迫切需要 break 語句的代碼片斷:
while 死循環
while (1) {
print "forever and ever..."
}
因為 1 永遠代表是真,這個 while 循環將永遠運行下去。以下是一個只執行十次的循環:
break 語句示例
x=1
while(1) {
print "iteration",x
if ( x == 10 ) {
break
}
x++
}
這裡,break 語句用於「逃出」最深層的循環。"break" 使循環立即終止,並繼續執行循環代碼塊後面的語句。
continue 語句補充了 break,其作用如下:
x=1
while (1) {
if ( x == 4 ) {
x++
continue
}
print "iteration",x
if ( x > 20 ) {
break
}
x++
}
這段代碼打印 "iteration 1" 到 "iteration 21","iteration 4" 除外。如果迭代等於 4,則增加 x 並調用 continue 語句,該語句立即使 awk 開始執行下一個循環迭代,而不執行代碼塊的其餘部分。如同 break 一樣,continue 語句適合各種 awk 迭代循環。在 for 循環主體中使用時,continue 將使循環控制變量自動增加。以下是一個等價循環:
for ( x=1; x<=21; x++ ) {
if ( x == 4 ) {
continue
}
print "iteration",x
}
在 while 循環中時,在調用 continue 之前沒有必要增加 x,因為 for 循環會自動增加 x。
數組
如果您知道 awk 可以使用數組,您一定會感到高興。然而,在 awk 中,數組下標通常從 1 開始,而不是 0:
myarray[1]="jim"
myarray[2]=456
awk 遇到第一個賦值語句時,它將創建 myarray,並將元素 myarray[1] 設置成 "jim"。執行了第二個賦值語句後,數組就有兩個元素了。
數組迭代
定義之後,awk 有一個便利的機制來迭代數組元素,如下所示:
for ( x in myarray ) {
print myarray[x]
}
這段代碼將打印數組 myarray 中的每一個元素。當對於 for 使用這種特殊的 "in" 形式時,awk 將 myarray 的每個現有下標依次賦值給 x(循環控制變量),每次賦值以後都循環一次循環代碼。雖然這是一個非常方便的 awk 功能,但它有一個缺點 -- 當 awk 在數組下標之間輪轉時,它不會依照任何特定的順序。那就意味著我們不能知道以上代碼的輸出是:
jim
456
還是
456
jim
套用 Forrest Gump 的話來說,迭代數組內容就像一盒巧克力 -- 您永遠不知道將會得到什麼。因此有必要使 awk 數組「字符串化」,我們現在就來研究這個問題。
數組下標字符串化
在我的前一篇文章中,我演示了 awk 實際上以字符串格式來存儲數字值。雖然 awk 要執行必要的轉換來完成這項工作,但它卻可以使用某些看起來很奇怪的代碼:
a="1"
b="2"
c=a+b+3
執行了這段代碼後,c 等於 6。由於 awk 是「字符串化」的,添加字符串 "1" 和 "2" 在功能上並不比添加數字 1 和 2 難。這兩種情況下,awk 都可以成功執行運算。awk 的「字符串化」性質非常可愛 -- 您可能想要知道如果使用數組的字符串下標會發生什麼情況。例如,使用以下代碼:
myarr["1"]="Mr. Whipple"
print myarr["1"]
可以預料,這段代碼將打印 "Mr. Whipple"。但如果去掉第二個 "1" 下標中的引號,情況又會怎樣呢?
myarr["1"]="Mr. Whipple"
print myarr[1]
猜想這個代碼片斷的結果比較難。awk 將 myarr["1"] 和 myarr[1] 看作數組的兩個獨立元素,還是它們是指同一個元素?答案是它們指的是同一個元素,awk 將打印 "Mr. Whipple",如同第一個代碼片斷一樣。雖然看上去可能有點怪,但 awk 在幕後卻一直使用數組的字符串下標!
瞭解了這個奇怪的真相之後,我們中的一些人可能想要執行類似於以下的古怪代碼:
myarr["name"]="Mr. Whipple"
print myarr["name"]
這段代碼不僅不會產生錯誤,而且它的功能與前面的示例完全相同,也將打印 "Mr. Whipple"!可以看到,awk 並沒有限制我們使用純整數下標;如果我們願意,可以使用字符串下標,而且不會產生任何問題。只要我們使用非整數數組下標,如 myarr["name"],那麼我們就在使用關聯數組。從技術上講,如果我們使用字符串下標,awk 的後台操作並沒有什麼不同(因為即便使用「整數」下標,awk 還是會將它看作是字符串)。但是,應該將它們稱作關聯數組 -- 它聽起來很酷,而且會給您的上司留下印象。字符串化下標是我們的小秘密。
數組工具
談到數組時,awk 給予我們許多靈活性。可以使用字符串下標,而且不需要連續的數字序列下標(例如,可以定義 myarr[1] 和 myarr[1000],但不定義其它所有元素)。雖然這些都很有用,但在某些情況下,會產生混淆。幸好,awk 提供了一些實用功能有助於使數組變得更易於管理。
首先,可以刪除數組元素。如果想要刪除數組 fooarray 的元素 1,輸入:
delete fooarray[1]
而且,如果想要查看是否存在某個特定數組元素,可以使用特殊的 "in" 布爾運算符,如下所示:
if ( 1 in fooarray ) {
print "Ayep! It's there."
} else {
print "Nope! Can't find it."
}
AWK SHELL FOR LINUX
[ 2006-6-23 14:07:00 | By: nathena ]
格式化輸出
雖然大多數情況下 awk 的 print 語句可以完成任務,但有時我們還需要更多。在那些情況下,awk 提供了兩個我們熟知的老朋友 printf() 和 sprintf()。是的,如同其它許多 awk 部件一樣,這些函數等同於相應的 C 語言函數。printf() 會將格式化字符串打印到 stdout,而 sprintf() 則返回可以賦值給變量的格式化字符串。如果不熟悉 printf() 和 sprintf(),介紹 C 語言的文章可以讓您迅速瞭解這兩個基本打印函數。在 Linux 系統上,可以輸入 "man 3 printf" 來查看 printf() 幫助頁面。
以下是一些 awk sprintf() 和 printf() 的樣本代碼。可以看到,它們幾乎與 C 語言完全相同。
x=1
b="foo"
printf("%s got a %d on the last test\n","Jim",83)
myout=("%s-%d",b,x)
print myout
此代碼將打印:
Jim got a 83 on the last test
foo-1
字符串函數
awk 有許多字符串函數,這是件好事。在 awk 中,確實需要字符串函數,因為不能像在其它語言(如 C、C++ 和 Python)中那樣將字符串看作是字符數組。例如,如果執行以下代碼:
mystring="How are you doing today?"
print mystring[3]
將會接收到一個錯誤,如下所示:
awk: string.gawk:59: fatal: attempt to use scalar as array
噢,好吧。雖然不像 Python 的序列類型那樣方便,但 awk 的字符串函數還是可以完成任務。讓我們來看一下。
首先,有一個基本 length() 函數,它返回字符串的長度。以下是它的使用方法:
print length(mystring)
此代碼將打印值:
24
好,繼續。下一個字符串函數叫作 index,它將返回子字符串在另一個字符串中出現的位置,如果沒有找到該字符串則返回 0。使用 mystring,可以按以下方法調用它:
print index(mystring,"you")
awk 會打印:
9
讓我們繼續討論另外兩個簡單的函數,tolower() 和 toupper()。與您猜想的一樣,這兩個函數將返回字符串並且將所有字符分別轉換成小寫或大寫。請注意,tolower() 和 toupper() 返回新的字符串,不會修改原來的字符串。這段代碼:
print tolower(mystring)
print toupper(mystring)
print mystring
……將產生以下輸出:
how are you doing today?
HOW ARE YOU DOING TODAY?
How are you doing today?
到現在為止一切不錯,但我們究竟如何從字符串中選擇子串,甚至單個字符?那就是使用 substr() 的原因。以下是 substr() 的調用方法:
mysub=substr(mystring,startpos,maxlen)
mystring 應該是要從中抽取子串的字符串變量或文字字符串。startpos 應該設置成起始字符位置,maxlen 應該包含要抽取的字符串的最大長度。請注意,我說的是最大長度;如果 length(mystring) 比 startpos+maxlen 短,那麼得到的結果就會被截斷。substr() 不會修改原始字符串,而是返回子串。以下是一個示例:
print substr(mystring,9,3)
awk 將打印:
you
如果您通常用於編程的語言使用數組下標訪問部分字符串(以及不使用這種語言的人),請記住 substr() 是 awk 代替方法。需要使用它來抽取單個字符和子串;因為 awk 是基於字符串的語言,所以會經常用到它。
現在,我們討論一些更耐人尋味的函數,首先是 match()。match() 與 index() 非常相似,它與 index() 的區別在於它並不搜索子串,它搜索的是規則表達式。match() 函數將返回匹配的起始位置,如果沒有找到匹配,則返回 0。此外,match() 還將設置兩個變量,叫作 RSTART 和 RLENGTH。RSTART 包含返回值(第一個匹配的位置),RLENGTH 指定它佔據的字符跨度(如果沒有找到匹配,則返回 -1)。通過使用 RSTART、RLENGTH、substr() 和一個小循環,可以輕鬆地迭代字符串中的每個匹配。以下是一個 match() 調用示例:
print match(mystring,/you/), RSTART, RLENGTH
awk 將打印:
9 9 3
字符串替換
現在,我們將研究兩個字符串替換函數,sub() 和 gsub()。這些函數與目前已經討論過的函數略有不同,因為它們確實修改原始字符串。以下是一個模板,顯示了如何調用 sub():
sub(regexp,replstring,mystring)
調用 sub() 時,它將在 mystring 中匹配 regexp 的第一個字符序列,並且用 replstring 替換該序列。sub() 和 gsub() 用相同的自變量;唯一的區別是 sub() 將替換第一個 regexp 匹配(如果有的話),gsub() 將執行全局替換,換出字符串中的所有匹配。以下是一個 sub() 和 gsub() 調用示例:
sub(/o/,"O",mystring)
print mystring
mystring="How are you doing today?"
gsub(/o/,"O",mystring)
print mystring
必須將 mystring 復位成其初始值,因為第一個 sub() 調用直接修改了 mystring。在執行時,此代碼將使 awk 輸出:
HOw are you doing today?
HOw are yOu dOing tOday?
當然,也可以是更複雜的規則表達式。我把測試一些複雜規則表達式的任務留給您來完成。
通過介紹函數 split(),我們來匯總一下已討論過的函數。split() 的任務是「切開」字符串,並將各部分放到使用整數下標的數組中。以下是一個 split() 調用示例:
numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")
調用 split() 時,第一個自變量包含要切開文字字符串或字符串變量。在第二個自變量中,應該指定 split() 將填入片段部分的數組名稱。在第三個元素中,指定用於切開字符串的分隔符。split() 返回時,它將返回分割的字符串元素的數量。split() 將每一個片段賦值給下標從 1 開始的數組,因此以下代碼:
print mymonths[1],mymonths[numelements]
……將打印:
Jan Dec
特殊字符串形式
簡短註釋 -- 調用 length()、sub() 或 gsub() 時,可以去掉最後一個自變量,這樣 awk 將對 $0(整個當前行)應用函數調用。要打印文件中每一行的長度,使用以下 awk 腳本:
{
print length()
}
財務上的趣事
幾星期前,我決定用 awk 編寫自己的支票簿結算程序。我決定使用簡單的 tab 定界文本文件,以便於輸入最近的存款和提款記錄。其思路是將這個數據交給 awk 腳本,該腳本會自動合計所有金額,並告訴我餘額。以下是我決定如何將所有交易記錄到 "ASCII checkbook" 中:
23 Aug 2000 food - - Y Jimmy's Buffet 30.25
此文件中的每個字段都由一個或多個 tab 分隔。在日期(字段 1,$1)之後,有兩個字段叫做「費用分類帳」和「收入分類帳」。以上面這行為例,輸入費用時,我在費用字段中放入四個字母的別名,在收入字段中放入 "-"(空白項)。這表示這一特定項是「食品費用」。 以下是存款的示例:
23 Aug 2000 - inco - Y Boss Man 2001.00
在這個實例中,我在費用分類帳中放入 "-"(空白),在收入分類帳中放入 "inco"。"inco" 是一般(薪水之類)收入的別名。使用分類帳別名讓我可以按類別生成收入和費用的明細分類帳。至於記錄的其餘部分,其它所有字段都是不需加以說明的。「是否付清?」字段("Y" 或 "N")記錄了交易是否已過帳到我的帳戶;除此之外,還有一個交易描述,和一個正的美元金額。
用於計算當前餘額的算法不太難。awk 只需要依次讀取每一行。如果列出了費用分類帳,但沒有收入分類帳(為 "-"),那麼這一項就是借方。如果列出了收入分類帳,但沒有費用分類帳(為 "-"),那麼這一項就是貸方。而且,如果同時列出了費用和收入分類帳,那麼這個金額就是「分類帳轉帳」;即,從費用分類帳減去美元金額,並將此金額添加到收入分類帳。此外,所有這些分類帳都是虛擬的,但對於跟蹤收入和支出以及預算卻非常有用。
代碼
現在該研究代碼了。我們將從第一行(BEGIN 塊和函數定義)開始:
balance,第 1 部分
#!/usr/bin/env awk -f
BEGIN {
FS="\t+"
months="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
}
function monthdigit(mymonth) {
return (index(months,mymonth)+3)/4
}
首先執行 "chmod +x myscript" 命令,那麼將第一行 "#!..." 添加到任何 awk 腳本將使它可以直接從 shell 中執行。其餘行定義了 BEGIN 塊,在 awk 開始處理支票簿文件之前將執行這個代碼塊。我們將 FS(字段分隔符)設置成 "\t+",它會告訴 awk 字段由一個或多個 tab 分隔。另外,我們定義了字符串 months,下面將出現的 monthdigit() 函數將使用它。
最後三行顯示了如何定義自己的 awk 。格式很簡單 -- 輸入 "function",再輸入名稱,然後在括號中輸入由逗號分隔的參數。在此之後,"{ }" 代碼塊包含了您希望這個函數執行的代碼。所有函數都可以訪問全局變量(如 months 變量)。另外,awk 提供了 "return" 語句,它允許函數返回一個值,並執行類似於 C 和其它語言中 "return" 的操作。這個特定函數將以 3 個字母字符串格式表示的月份名稱轉換成等價的數值。例如,以下代碼:
print monthdigit("Mar")
……將打印:
3
現在,讓我們討論其它一些函數。
財務函數
以下是其它三個執行簿記的函數。我們即將見到的主代碼塊將調用這些函數之一,按順序處理支票簿文件的每一行,從而將相應交易記錄到 awk 數組中。有三種基本交易,貸方 (doincome)、借方 (doexpense) 和轉帳 (dotransfer)。您會發現這三個函數全都接受一個自變量,叫作 mybalance。mybalance 是二維數組的一個佔位符,我們將它作為自變量進行傳遞。目前,我們還沒有處理過二維數組;但是,在下面可以看到,語法非常簡單。只須用逗號分隔每一維就行了。
我們將按以下方式將信息記錄到 "mybalance" 中。數組的第一維從 0 到 12,用於指定月份,0 代表全年。第二維是四個字母的分類帳,如 "food" 或 "inco";這是我們處理的真實分類帳。因此,要查找全年食品分類帳的餘額,應查看 mybalance[0,"food"]。要查找 6 月的收入,應查看 mybalance[6,"inco"]。
balance,第 2 部分
function doincome(mybalance) {
mybalance[curmonth,$3] += amount
mybalance[0,$3] += amount
}
function doexpense(mybalance) {
mybalance[curmonth,$2] -= amount
mybalance[0,$2] -= amount
}
function dotransfer(mybalance) {
mybalance[0,$2] -= amount
mybalance[curmonth,$2] -= amount
mybalance[0,$3] += amount
mybalance[curmonth,$3] += amount
}
調用 doincome() 或任何其它函數時,我們將交易記錄到兩個位置 -- mybalance[0,category] 和 mybalance[curmonth, category],它們分別表示全年的分類帳餘額和當月的分類帳餘額。這讓我們稍後可以輕鬆地生成年度或月度收入/支出明細分類帳。
如果研究這些函數,將發現在我的引用中傳遞了 mybalance 引用的數組。另外,我們還引用了幾個全局變量:curmonth,它保存了當前記錄所屬的月份的數值,$2(費用分類帳),$3(收入分類帳)和金額($7,美元金額)。調用 doincome() 和其它函數時,已經為要處理的當前記錄(行)正確設置了所有這些變量。
主塊
以下是主代碼塊,它包含了分析每一行輸入數據的代碼。請記住,由於正確設置了 FS,可以用 $ 1 引用第一個字段,用 $2 引用第二個字段,依次類推。調用 doincome() 和其它函數時,這些函數可以從函數內部訪問 curmonth、$2、$3 和金額的當前值。請先研究代碼,在代碼之後可以見到我的說明。
balance,第 3 部分
{
curmonth=monthdigit(substr($1,4,3))
amount=$7
#record all the categories encountered
if ( $2 != "-" )
globcat[$2]="yes"
if ( $3 != "-" )
globcat[$3]="yes"
#tally up the transaction properly
if ( $2 == "-" ) {
if ( $3 == "-" ) {
print "Error: inc and exp fields are both blank!"
exit 1
} else {
#this is income
doincome(balance)
if ( $5 == "Y" )
doincome(balance2)
}
} else if ( $3 == "-" ) {
#this is an expense
doexpense(balance)
if ( $5 == "Y" )
doexpense(balance2)
} else {
#this is a transfer
dotransfer(balance)
if ( $5 == "Y" )
dotransfer(balance2)
}
}
在主塊中,前兩行將 curmonth 設置成 1 到 12 之間的整數,並將金額設置成字段 7(使代碼易於理解)。然後,是四行有趣的代碼,它們將值寫到數組 globcat 中。globcat,或稱作全局分類帳數組,用於記錄在文件中遇到的所有分類帳 -- "inco"、"misc"、"food"、"util" 等。例如,如果 $2 == "inco",則將 globcat["inco"] 設置成 "yes"。稍後,我們可以使用簡單的 "for (x in globcat)" 循環來迭代分類帳列表。
在接著的大約二十行中,我們分析字段 $2 和 $3,並適當記錄交易。如果 $2=="-" 且 $3!="-",表示我們有收入,因此調用 doincome()。如果是相反的情況,則調用 doexpense();如果 $2 和 $3 都包含分類帳,則調用 dotransfer()。每次我們都將 "balance" 數組傳遞給這些函數,從而在這些函數中記錄適當的數據。
您還會發現幾行代碼說「if ( $5 == "Y" ),那麼將同一個交易記錄到 balance2 中」。我們在這裡究竟做了些什麼?您將回憶起 $5 包含 "Y" 或 "N",並記錄交易是否已經過帳到帳戶。由於僅當過帳了交易時我們才將交易記錄到 balance2,因此 balance2 包含了真實的帳戶餘額,而 "balance" 包含了所有交易,不管是否已經過帳。可以使用 balance2 來驗證數據項(因為它應該與當前銀行帳戶餘額匹配),可以使用 "balance" 來確保沒有透支帳戶(因為它會考慮您開出的尚未兌現的所有支票)。
生成報表
主塊重複處理了每一行記錄之後,現在我們有了關於比較全面的、按分類帳和按月份劃分的借方和貸方記錄。現在,在這種情況下最合適的做法是只須定義生成報表的 END 塊:
balance,第 4 部分
END {
bal=0
bal2=0
for (x in globcat) {
bal=bal+balance[0,x]
bal2=bal2+balance2[0,x]
}
printf("Your available funds: %10.2f\n", bal)
printf("Your account balance: %10.2f\n", bal2)
}
這個報表將打印出匯總,如下所示:
Your available funds:1174.22
Your account balance:2399.33
在 END 塊中,我們使用 "for (x in globcat)" 結構來迭代每一個分類帳,根據記錄在案的交易結算主要餘額。實際上,我們結算兩個餘額,一個是可用資金,另一個是帳戶餘額。要執行程序並處理您在文件 "mycheckbook.txt" 中輸入的財務數據,將以上所有代碼放入文本文件 "balance",執行 "chmod +x balance",然後輸入 "./balance mycheckbook.txt"。然後 balance 腳本將合計所有交易,打印出兩行餘額匯總。
在命令行中輸入以下命令:
$ awk '{ print }' /etc/passwd
您將會見到 /etc/passwd 文件的內容出現在眼前。現在,解釋 awk 做了些什麼。調用 awk 時,我們指定 /etc/passwd 作為輸入文件。執行 awk 時,它依次對 /etc/passwd 中的每一行執行 print 命令。所有輸出都發送到 stdout,所得到的結果與與執行catting /etc/passwd完全相同。
現在,解釋 { print } 代碼塊。在 awk 中,花括號用於將幾塊代碼組合到一起,這一點類似於 C 語言。在代碼塊中只有一條 print 命令。在 awk 中,如果只出現 print 命令,那麼將打印當前行的全部內容。
這裡是另一個 awk 示例,它的作用與上例完全相同:
$ awk '{ print $0 }' /etc/passwd
在 awk 中,$0 變量表示整個當前行,所以 print 和 print $0 的作用完全一樣。
如果您願意,可以創建一個 awk 程序,讓它輸出與輸入數據完全無關的數據。以下是一個示例:
$ awk '{ print "" }' /etc/passwd
只要將 "" 字符串傳遞給 print 命令,它就會打印空白行。如果測試該腳本,將會發現對於 /etc/passwd 文件中的每一行,awk 都輸出一個空白行。再次說明, awk 對輸入文件中的每一行都執行這個腳本。以下是另一個示例:
$ awk '{ print "hiya" }' /etc/passwd
運行這個腳本將在您的屏幕上寫滿 hiya。
多個字段
awk 非常善於處理分成多個邏輯字段的文本,而且讓您可以毫不費力地引用 awk 腳本中每個獨立的字段。以下腳本將打印出您的系統上所有用戶帳戶的列表:
$ awk -F":" '{ print $1 }' /etc/passwd
上例中,在調用 awk 時,使用 -F 選項來指定 ":" 作為字段分隔符。awk 處理 print $1 命令時,它會打印出在輸入文件中每一行中出現的第一個字段。以下是另一個示例:
$ awk -F":" '{ print $1 $3 }' /etc/passwd
以下是該腳本輸出的摘錄:
halt7
operator11
root0
shutdown6
sync5
bin1
....etc.
如您所見,awk 打印出 /etc/passwd 文件的第一和第三個字段,它們正好分別是用戶名和用戶標識字段。現在,當腳本運行時,它並不理想 -- 在兩個輸出字段之間沒有空格!如果習慣於使用 bash 或 python 進行編程,那麼您會指望 print $1 $3 命令在兩個字段之間插入空格。然而,當兩個字符串在 awk 程序中彼此相鄰時,awk 會連接它們但不在它們之間添加空格。以下命令會在這兩個字段中插入空格:
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
以這種方式調用 print 時,它將連接 $1、" " 和 $3,創建可讀的輸出。當然,如果需要的話,我們還可以插入一些文本標籤:
$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
這將產生以下輸出:
username: halt uid:7
username: operator uid:11
username: root uid:0
username: shutdown uid:6
username: sync uid:5
username: bin uid:1
....etc.
外部腳本
將腳本作為命令行自變量傳遞給 awk 對於小的單行程序來說是非常簡單的,而對於多行程序,它就比較複雜。您肯定想要在外部文件中撰寫腳本。然後可以向 awk 傳遞 -f 選項,以向它提供此腳本文件:
$ awk -f myscript.awk myfile.in
將腳本放入文本文件還可以讓您使用附加 awk 功能。例如,這個多行腳本與前面的單行腳本的作用相同,它們都打印出 /etc/passwd 中每一行的第一個字段:
BEGIN {
FS=":"
}
{ print $1 }
這兩個方法的差別在於如何設置字段分隔符。在這個腳本中,字段分隔符在代碼自身中指定(通過設置 FS 變量),而在前一個示例中,通過在命令行上向 awk 傳遞 -F":" 選項來設置 FS。通常,最好在腳本自身中設置字段分隔符,只是因為這表示您可以少輸入一個命令行自變量。我們將在本文的後面詳細討論 FS 變量。
BEGIN 和 END 塊
通常,對於每個輸入行,awk 都會執行每個腳本代碼塊一次。然而,在許多編程情況中,可能需要在 awk 開始處理輸入文件中的文本之前執行初始化代碼。對於這種情況,awk 允許您定義一個 BEGIN 塊。我們在前一個示例中使用了 BEGIN 塊。因為 awk 在開始處理輸入文件之前會執行 BEGIN 塊,因此它是初始化 FS(字段分隔符)變量、打印頁眉或初始化其它在程序中以後會引用的全局變量的極佳位置。
awk 還提供了另一個特殊塊,叫作 END 塊。awk 在處理了輸入文件中的所有行之後執行這個塊。通常,END 塊用於執行最終計算或打印應該出現在輸出流結尾的摘要信息。
規則表達式和塊
awk 允許使用規則表達式,根據規則表達式是否匹配當前行來選擇執行獨立代碼塊。以下示例腳本只輸出包含字符序列 foo 的那些行:
/foo/ { print }
當然,可以使用更複雜的規則表達式。以下腳本將只打印包含浮點數的行:
/[0-9]+\.[0-9]*/ { print }
表達式和塊
還有許多其它方法可以選擇執行代碼塊。我們可以將任意一種布爾表達式放在一個代碼塊之前,以控制何時執行某特定塊。僅當對前面的布爾表達式求值為真時,awk 才執行代碼塊。以下示例腳本輸出將輸出其第一個字段等於 fred 的所有行中的第三個字段。如果當前行的第一個字段不等於 fred,awk 將繼續處理文件而不對當前行執行 print 語句:
$1 == "fred" { print $3 }
awk 提供了完整的比較運算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 還提供了 "~" 和 "!~" 運算符,它們分別表示「匹配」和「不匹配」。它們的用法是在運算符左邊指定變量,在右邊指定規則表達式。如果某一行的第五個字段包含字符序列 root,那麼以下示例將只打印這一行中的第三個字段:
$5 ~ /root/ { print $3 }
條件語句
awk 還提供了非常好的類似於 C 語言的 if 語句。如果您願意,可以使用 if 語句重寫前一個腳本:
{
if ( $5 ~ /root/ ) {
print $3
}
}
這兩個腳本的功能完全一樣。第一個示例中,布爾表達式放在代碼塊外面。而在第二個示例中,將對每一個輸入行執行代碼塊,而且我們使用 if 語句來選擇執行 print 命令。這兩個方法都可以使用,可以選擇最適合腳本其它部分的一種方法。
以下是更複雜的 awk if 語句示例。可以看到,儘管使用了複雜、嵌套的條件語句,if 語句看上去仍與相應的 C 語言 if 語句一樣:
{
if ( $1 == "foo" ) {
if ( $2 == "foo" ) {
print "uno"
} else {
print "one"
}
} else if ($1 == "bar" ) {
print "two"
} else {
print "three"
}
}
使用 if 語句還可以將代碼:
! /matchme/ { print $1 $3 $4 }
轉換成:
{
if ( $0 !~ /matchme/ ) {
print $1 $3 $4
}
}
這兩個腳本都只輸出不包含 matchme 字符序列的那些行。此外,還可以選擇最適合您的代碼的方法。它們的功能完全相同。
awk 還允許使用布爾運算符 "||"(邏輯與)和 "&&"(邏輯或),以便創建更複雜的布爾表達式:
( $1 == "foo" ) && ( $2 == "bar" ) { print }
這個示例只打印第一個字段等於 foo 且第二個字段等於 bar 的那些行。
數值變量!
至今,我們不是打印字符串、整行就是特定字段。然而,awk 還允許我們執行整數和浮點運算。通過使用數學表達式,可以很方便地編寫計算文件中空白行數量的腳本。以下就是這樣一個腳本:
BEGIN { x=0 }
/^$/ { x=x+1 }
END { print "I found " x " blank lines. " }
在 BEGIN 塊中,將整數變量 x 初始化成零。然後,awk 每次遇到空白行時,awk 將執行 x=x+1 語句,遞增 x。處理完所有行之後,執行 END 塊,awk 將打印出最終摘要,指出它找到的空白行數量。
字符串化變量
awk 的優點之一就是「簡單和字符串化」。我認為 awk 變量「字符串化」是因為所有 awk 變量在內部都是按字符串形式存儲的。同時,awk 變量是「簡單的」,因為可以對它執行數學操作,且只要變量包含有效數字字符串,awk 會自動處理字符串到數字的轉換步驟。要理解我的觀點,請研究以下這個示例:
x="1.01"
# We just set x to contain the *string* "1.01"
x=x+1
# We just added one to a *string*
print x
# Incidentally, these are comments
awk 將輸出:
2.01
有趣吧!雖然將字符串值 1.01 賦值給變量 x,我們仍然可以對它加一。但在 bash 和 python 中卻不能這樣做。首先,bash 不支持浮點運算。而且,如果 bash 有「字符串化」變量,它們並不「簡單」;要執行任何數學操作,bash 要求我們將數字放到醜陋的 $( ) ) 結構中。如果使用 python,則必須在對 1.01 字符串執行任何數學運算之前,將它轉換成浮點值。雖然這並不困難,但它仍是附加的步驟。如果使用 awk,它是全自動的,而那會使我們的代碼又好又整潔。如果想要對每個輸入行的第一個字段乘方並加一,可以使用以下腳本:
{ print ($1^2)+1 }
如果做一個小實驗,就可以發現如果某個特定變量不包含有效數字,awk 在對數學表達式求值時會將該變量當作數字零處理。
眾多運算符
awk 的另一個優點是它有完整的數學運算符集合。除了標準的加、減、乘、除,awk 還允許使用前面演示過的指數運算符 "^"、模(餘數)運算符 "%" 和其它許多從 C 語言中借入的易於使用的賦值操作符。
這些運算符包括前後加減(i++、--foo)、加/減/乘/除賦值運算符( a+=3、b*=2、c/=2.2、d-=6.2)。不僅如此 -- 我們還有易於使用的模/指數賦值運算符(a^=2、b%=4)。
字段分隔符
awk 有它自己的特殊變量集合。其中一些允許調整 awk 的運行方式,而其它變量可以被讀取以收集關於輸入的有用信息。我們已經接觸過這些特殊變量中的一個,FS。前面已經提到過,這個變量讓您可以設置 awk 要查找的字段之間的字符序列。我們使用 /etc/passwd 作為輸入時,將 FS 設置成 ":"。當這樣做有問題時,我們還可以更靈活地使用 FS。
FS 值並沒有被限制為單一字符;可以通過指定任意長度的字符模式,將它設置成規則表達式。如果正在處理由一個或多個 tab 分隔的字段,您可能希望按以下方式設置 FS:
FS="\t+"
以上示例中,我們使用特殊 "+" 規則表達式字符,它表示「一個或多個前一字符」。
如果字段由空格分隔(一個或多個空格或 tab),您可能想要將 FS 設置成以下規則表達式:
FS="[[:space:]+]"
這個賦值表達式也有問題,它並非必要。為什麼?因為缺省情況下,FS 設置成單一空格字符,awk 將這解釋成表示「一個或多個空格或 tab」。在這個特殊示例中,缺省 FS 設置恰恰是您最想要的!
複雜的規則表達式也不成問題。即使您的記錄由單詞 "foo" 分隔,後面跟著三個數字,以下規則表達式仍允許對數據進行正確的分析:
FS="foo[0-9][0-9][0-9]"
字段數量
接著我們要討論的兩個變量通常並不是需要賦值的,而是用來讀取以獲取關於輸入的有用信息。第一個是 NF 變量,也叫做「字段數量」變量。awk 會自動將該變量設置成當前記錄中的字段數量。可以使用 NF 變量來只顯示某些輸入行:
NF == 3 { print "this particular record has three fields: " $0 }
當然,也可以在條件語句中使用 NF 變量,如下:
{
if ( NF > 2 ) {
print $1 " " $2 ":" $3
}
}
記錄號
記錄號 (NR) 是另一個方便的變量。它始終包含當前記錄的編號(awk 將第一個記錄算作記錄號 1)。迄今為止,我們已經處理了每一行包含一個記錄的輸入文件。對於這些情況,NR 還會告訴您當前行號。然而,當我們在本系列以後部分中開始處理多行記錄時,就不會再有這種情況,所以要注意!可以像使用 NF 變量一樣使用 NR 來只打印某些輸入行:
(NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" }
另一個示例:
{
#skip header
if ( NR > 10 ) {
print "ok, now for the real information!"
}
}
AWK SHELL FOR LINUX
[ 2006-6-23 14:06:00 | By: nathena ]
多行記錄
awk 是一種用於讀取和處理結構化數據(如系統的 /etc/passwd 文件)的極佳工具。/etc/passwd 是 UNIX 用戶數據庫,並且是用冒號定界的文本文件,它包含許多重要信息,包括所有現有用戶帳戶和用戶標識,以及其它信息。在我的前一篇文章中,我演示了 awk 如何輕鬆地分析這個文件。我們只須將 FS(字段分隔符)變量設置成 ":"。
正確設置了 FS 變量之後,就可以將 awk 配置成分析幾乎任何類型的結構化數據,只要這些數據是每行一個記錄。然而,如果要分析佔據多行的記錄,僅僅依靠設置 FS 是不夠的。在這些情況下,我們還需要修改 RS 記錄分隔符變量。RS 變量告訴 awk 當前記錄什麼時候結束,新記錄什麼時候開始。
譬如,讓我們討論一下如何完成處理「聯邦證人保護計劃」所涉及人員的地址列表的任務:
Jimmy the Weasel
100 Pleasant Drive
San Francisco, CA 12345
Big Tony
200 Incognito Ave.
Suburbia, WA 67890
理論上,我們希望 awk 將每 3 行看作是一個獨立的記錄,而不是三個獨立的記錄。如果 awk 將地址的第一行看作是第一個字段 ($1),街道地址看作是第二個字段 ($2),城市、州和郵政編碼看作是第三個字段 $3,那麼這個代碼就會變得很簡單。以下就是我們想要得到的代碼:
BEGIN {
FS="\n"
RS=""
}
在上面這段代碼中,將 FS 設置成 "\n" 告訴 awk 每個字段都佔據一行。通過將 RS 設置成 "",還會告訴 awk 每個地址記錄都由空白行分隔。一旦 awk 知道是如何格式化輸入的,它就可以為我們執行所有分析工作,腳本的其餘部分很簡單。讓我們研究一個完整的腳本,它將分析這個地址列表,並將每個記錄打印在一行上,用逗號分隔每個字段。
address.awk
BEGIN {
FS="\n"
RS=""
}
{
print $1 ", " $2 ", " $3
}
如果這個腳本保存為 address.awk,地址數據存儲在文件 address.txt 中,可以通過輸入 "awk -f address.awk address.txt" 來執行這個腳本。此代碼將產生以下輸出:
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
OFS 和 ORS
在 address.awk 的 print 語句中,可以看到 awk 會連接(合併)一行中彼此相鄰的字符串。我們使用此功能在同一行上的三個字段之間插入一個逗號和空格 (", ")。這個方法雖然有用,但比較難看。與其在字段間插入 ", " 字符串,倒不如讓通過設置一個特殊 awk 變量 OFS,讓 awk 完成這件事。請參考下面這個代碼片斷。
print "Hello", "there", "Jim!"
這行代碼中的逗號並不是實際文字字符串的一部分。事實上,它們告訴 awk "Hello"、"there" 和 "Jim!" 是單獨的字段,並且應該在每個字符串之間打印 OFS 變量。缺省情況下,awk 產生以下輸出:
Hello there Jim!
這是缺省情況下的輸出結果,OFS 被設置成 " ",單個空格。不過,我們可以方便地重新定義 OFS,這樣 awk 將插入我們中意的字段分隔符。以下是原始 address.awk 程序的修訂版,它使用 OFS 來輸出那些中間的 ", " 字符串:
address.awk 的修訂版
BEGIN {
FS="\n"
RS=""
OFS=", "
}
{
print $1, $2, $3
}
awk 還有一個特殊變量 ORS,全稱是「輸出記錄分隔符」。通過設置缺省為換行 ("\n") 的 OFS,我們可以控制在 print 語句結尾自動打印的字符。缺省 ORS 值會使 awk 在新行中輸出每個新的 print 語句。如果想使輸出的間隔翻倍,可以將 ORS 設置成 "\n\n"。或者,如果想要用單個空格分隔記錄(而不換行),將 ORS 設置成 ""。
將多行轉換成用 tab 分隔的格式
假設我們編寫了一個腳本,它將地址列表轉換成每個記錄一行,且用 tab 定界的格式,以便導入電子錶格。使用稍加修改的 address.awk 之後,就可以清楚地看到這個程序只適合於三行的地址。如果 awk 遇到以下地址,將丟掉第四行,並且不打印該行:
Cousin Vinnie
Vinnie's Auto Shop
300 City Alley
Sosueme, OR 76543
要處理這種情況,代碼最好考慮每個字段的記錄數量,並依次打印每個記錄。現在,代碼只打印地址的前三個字段。以下就是我們想要的一些代碼:
適合具有任意多字段的地址的 address.awk 版本
BEGIN {
FS="\n"
RS=""
ORS=""
}
{
x=1
while ( x<NF ) {
print $x "\t"
x++
}
print $NF "\n"
}
首先,將字段分隔符 FS 設置成 "\n",將記錄分隔符 RS 設置成 "",這樣 awk 可以像以前一樣正確分析多行地址。然後,將輸出記錄分隔符 ORS 設置成 "",它將使 print 語句在每個調用結尾不輸出新行。這意味著如果希望任何文本從新的一行開始,那麼需要明確寫入 print "\n"。
在主代碼塊中,創建了一個變量 x 來存儲正在處理的當前字段的編號。起初,它被設置成 1。然後,我們使用 while 循環(一種 awk 循環結構,等同於 C 語言中的 while 循環),對於所有記錄(最後一個記錄除外)重複打印記錄和 tab 字符。最後,打印最後一個記錄和換行;此外,由於將 ORS 設置成 "",print 將不輸出換行。程序輸出如下,這正是我們所期望的:
我們想要的輸出。不算漂亮,但用 tab 定界,以便於導入電子錶格
Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345
Big Tony 200 Incognito Ave. Suburbia, WA 67890
Cousin Vinnie Vinnie's Auto Shop 300 City Alley Sosueme, OR 76543
循環結構
我們已經看到了 awk 的 while 循環結構,它等同於相應的 C 語言 while 循環。awk 還有 "do...while" 循環,它在代碼塊結尾處對條件求值,而不像標準 while 循環那樣在開始處求值。它類似於其它語言中的 "repeat...until" 循環。以下是一個示例:
do...while 示例
{
count=1
do {
print "I get printed at least once no matter what"
} while ( count != 1 )
}
與一般的 while 循環不同,由於在代碼塊之後對條件求值,"do...while" 循環永遠都至少執行一次。換句話說,當第一次遇到普通 while 循環時,如果條件為假,將永遠不執行該循環。
for 循環
awk 允許創建 for 循環,它就像 while 循環,也等同於 C 語言的 for 循環:
for ( initial assignment; comparison; increment ) {
code block
}
以下是一個簡短示例:
for ( x = 1; x <= 4; x++ ) {
print "iteration",x
}
此段代碼將打印:
iteration 1
iteration 2
iteration 3
iteration 4
break 和 continue
此外,如同 C 語言一樣,awk 提供了 break 和 continue 語句。使用這些語句可以更好地控制 awk 的循環結構。以下是迫切需要 break 語句的代碼片斷:
while 死循環
while (1) {
print "forever and ever..."
}
因為 1 永遠代表是真,這個 while 循環將永遠運行下去。以下是一個只執行十次的循環:
break 語句示例
x=1
while(1) {
print "iteration",x
if ( x == 10 ) {
break
}
x++
}
這裡,break 語句用於「逃出」最深層的循環。"break" 使循環立即終止,並繼續執行循環代碼塊後面的語句。
continue 語句補充了 break,其作用如下:
x=1
while (1) {
if ( x == 4 ) {
x++
continue
}
print "iteration",x
if ( x > 20 ) {
break
}
x++
}
這段代碼打印 "iteration 1" 到 "iteration 21","iteration 4" 除外。如果迭代等於 4,則增加 x 並調用 continue 語句,該語句立即使 awk 開始執行下一個循環迭代,而不執行代碼塊的其餘部分。如同 break 一樣,continue 語句適合各種 awk 迭代循環。在 for 循環主體中使用時,continue 將使循環控制變量自動增加。以下是一個等價循環:
for ( x=1; x<=21; x++ ) {
if ( x == 4 ) {
continue
}
print "iteration",x
}
在 while 循環中時,在調用 continue 之前沒有必要增加 x,因為 for 循環會自動增加 x。
數組
如果您知道 awk 可以使用數組,您一定會感到高興。然而,在 awk 中,數組下標通常從 1 開始,而不是 0:
myarray[1]="jim"
myarray[2]=456
awk 遇到第一個賦值語句時,它將創建 myarray,並將元素 myarray[1] 設置成 "jim"。執行了第二個賦值語句後,數組就有兩個元素了。
數組迭代
定義之後,awk 有一個便利的機制來迭代數組元素,如下所示:
for ( x in myarray ) {
print myarray[x]
}
這段代碼將打印數組 myarray 中的每一個元素。當對於 for 使用這種特殊的 "in" 形式時,awk 將 myarray 的每個現有下標依次賦值給 x(循環控制變量),每次賦值以後都循環一次循環代碼。雖然這是一個非常方便的 awk 功能,但它有一個缺點 -- 當 awk 在數組下標之間輪轉時,它不會依照任何特定的順序。那就意味著我們不能知道以上代碼的輸出是:
jim
456
還是
456
jim
套用 Forrest Gump 的話來說,迭代數組內容就像一盒巧克力 -- 您永遠不知道將會得到什麼。因此有必要使 awk 數組「字符串化」,我們現在就來研究這個問題。
數組下標字符串化
在我的前一篇文章中,我演示了 awk 實際上以字符串格式來存儲數字值。雖然 awk 要執行必要的轉換來完成這項工作,但它卻可以使用某些看起來很奇怪的代碼:
a="1"
b="2"
c=a+b+3
執行了這段代碼後,c 等於 6。由於 awk 是「字符串化」的,添加字符串 "1" 和 "2" 在功能上並不比添加數字 1 和 2 難。這兩種情況下,awk 都可以成功執行運算。awk 的「字符串化」性質非常可愛 -- 您可能想要知道如果使用數組的字符串下標會發生什麼情況。例如,使用以下代碼:
myarr["1"]="Mr. Whipple"
print myarr["1"]
可以預料,這段代碼將打印 "Mr. Whipple"。但如果去掉第二個 "1" 下標中的引號,情況又會怎樣呢?
myarr["1"]="Mr. Whipple"
print myarr[1]
猜想這個代碼片斷的結果比較難。awk 將 myarr["1"] 和 myarr[1] 看作數組的兩個獨立元素,還是它們是指同一個元素?答案是它們指的是同一個元素,awk 將打印 "Mr. Whipple",如同第一個代碼片斷一樣。雖然看上去可能有點怪,但 awk 在幕後卻一直使用數組的字符串下標!
瞭解了這個奇怪的真相之後,我們中的一些人可能想要執行類似於以下的古怪代碼:
myarr["name"]="Mr. Whipple"
print myarr["name"]
這段代碼不僅不會產生錯誤,而且它的功能與前面的示例完全相同,也將打印 "Mr. Whipple"!可以看到,awk 並沒有限制我們使用純整數下標;如果我們願意,可以使用字符串下標,而且不會產生任何問題。只要我們使用非整數數組下標,如 myarr["name"],那麼我們就在使用關聯數組。從技術上講,如果我們使用字符串下標,awk 的後台操作並沒有什麼不同(因為即便使用「整數」下標,awk 還是會將它看作是字符串)。但是,應該將它們稱作關聯數組 -- 它聽起來很酷,而且會給您的上司留下印象。字符串化下標是我們的小秘密。
數組工具
談到數組時,awk 給予我們許多靈活性。可以使用字符串下標,而且不需要連續的數字序列下標(例如,可以定義 myarr[1] 和 myarr[1000],但不定義其它所有元素)。雖然這些都很有用,但在某些情況下,會產生混淆。幸好,awk 提供了一些實用功能有助於使數組變得更易於管理。
首先,可以刪除數組元素。如果想要刪除數組 fooarray 的元素 1,輸入:
delete fooarray[1]
而且,如果想要查看是否存在某個特定數組元素,可以使用特殊的 "in" 布爾運算符,如下所示:
if ( 1 in fooarray ) {
print "Ayep! It's there."
} else {
print "Nope! Can't find it."
}
AWK SHELL FOR LINUX
[ 2006-6-23 14:07:00 | By: nathena ]
格式化輸出
雖然大多數情況下 awk 的 print 語句可以完成任務,但有時我們還需要更多。在那些情況下,awk 提供了兩個我們熟知的老朋友 printf() 和 sprintf()。是的,如同其它許多 awk 部件一樣,這些函數等同於相應的 C 語言函數。printf() 會將格式化字符串打印到 stdout,而 sprintf() 則返回可以賦值給變量的格式化字符串。如果不熟悉 printf() 和 sprintf(),介紹 C 語言的文章可以讓您迅速瞭解這兩個基本打印函數。在 Linux 系統上,可以輸入 "man 3 printf" 來查看 printf() 幫助頁面。
以下是一些 awk sprintf() 和 printf() 的樣本代碼。可以看到,它們幾乎與 C 語言完全相同。
x=1
b="foo"
printf("%s got a %d on the last test\n","Jim",83)
myout=("%s-%d",b,x)
print myout
此代碼將打印:
Jim got a 83 on the last test
foo-1
字符串函數
awk 有許多字符串函數,這是件好事。在 awk 中,確實需要字符串函數,因為不能像在其它語言(如 C、C++ 和 Python)中那樣將字符串看作是字符數組。例如,如果執行以下代碼:
mystring="How are you doing today?"
print mystring[3]
將會接收到一個錯誤,如下所示:
awk: string.gawk:59: fatal: attempt to use scalar as array
噢,好吧。雖然不像 Python 的序列類型那樣方便,但 awk 的字符串函數還是可以完成任務。讓我們來看一下。
首先,有一個基本 length() 函數,它返回字符串的長度。以下是它的使用方法:
print length(mystring)
此代碼將打印值:
24
好,繼續。下一個字符串函數叫作 index,它將返回子字符串在另一個字符串中出現的位置,如果沒有找到該字符串則返回 0。使用 mystring,可以按以下方法調用它:
print index(mystring,"you")
awk 會打印:
9
讓我們繼續討論另外兩個簡單的函數,tolower() 和 toupper()。與您猜想的一樣,這兩個函數將返回字符串並且將所有字符分別轉換成小寫或大寫。請注意,tolower() 和 toupper() 返回新的字符串,不會修改原來的字符串。這段代碼:
print tolower(mystring)
print toupper(mystring)
print mystring
……將產生以下輸出:
how are you doing today?
HOW ARE YOU DOING TODAY?
How are you doing today?
到現在為止一切不錯,但我們究竟如何從字符串中選擇子串,甚至單個字符?那就是使用 substr() 的原因。以下是 substr() 的調用方法:
mysub=substr(mystring,startpos,maxlen)
mystring 應該是要從中抽取子串的字符串變量或文字字符串。startpos 應該設置成起始字符位置,maxlen 應該包含要抽取的字符串的最大長度。請注意,我說的是最大長度;如果 length(mystring) 比 startpos+maxlen 短,那麼得到的結果就會被截斷。substr() 不會修改原始字符串,而是返回子串。以下是一個示例:
print substr(mystring,9,3)
awk 將打印:
you
如果您通常用於編程的語言使用數組下標訪問部分字符串(以及不使用這種語言的人),請記住 substr() 是 awk 代替方法。需要使用它來抽取單個字符和子串;因為 awk 是基於字符串的語言,所以會經常用到它。
現在,我們討論一些更耐人尋味的函數,首先是 match()。match() 與 index() 非常相似,它與 index() 的區別在於它並不搜索子串,它搜索的是規則表達式。match() 函數將返回匹配的起始位置,如果沒有找到匹配,則返回 0。此外,match() 還將設置兩個變量,叫作 RSTART 和 RLENGTH。RSTART 包含返回值(第一個匹配的位置),RLENGTH 指定它佔據的字符跨度(如果沒有找到匹配,則返回 -1)。通過使用 RSTART、RLENGTH、substr() 和一個小循環,可以輕鬆地迭代字符串中的每個匹配。以下是一個 match() 調用示例:
print match(mystring,/you/), RSTART, RLENGTH
awk 將打印:
9 9 3
字符串替換
現在,我們將研究兩個字符串替換函數,sub() 和 gsub()。這些函數與目前已經討論過的函數略有不同,因為它們確實修改原始字符串。以下是一個模板,顯示了如何調用 sub():
sub(regexp,replstring,mystring)
調用 sub() 時,它將在 mystring 中匹配 regexp 的第一個字符序列,並且用 replstring 替換該序列。sub() 和 gsub() 用相同的自變量;唯一的區別是 sub() 將替換第一個 regexp 匹配(如果有的話),gsub() 將執行全局替換,換出字符串中的所有匹配。以下是一個 sub() 和 gsub() 調用示例:
sub(/o/,"O",mystring)
print mystring
mystring="How are you doing today?"
gsub(/o/,"O",mystring)
print mystring
必須將 mystring 復位成其初始值,因為第一個 sub() 調用直接修改了 mystring。在執行時,此代碼將使 awk 輸出:
HOw are you doing today?
HOw are yOu dOing tOday?
當然,也可以是更複雜的規則表達式。我把測試一些複雜規則表達式的任務留給您來完成。
通過介紹函數 split(),我們來匯總一下已討論過的函數。split() 的任務是「切開」字符串,並將各部分放到使用整數下標的數組中。以下是一個 split() 調用示例:
numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")
調用 split() 時,第一個自變量包含要切開文字字符串或字符串變量。在第二個自變量中,應該指定 split() 將填入片段部分的數組名稱。在第三個元素中,指定用於切開字符串的分隔符。split() 返回時,它將返回分割的字符串元素的數量。split() 將每一個片段賦值給下標從 1 開始的數組,因此以下代碼:
print mymonths[1],mymonths[numelements]
……將打印:
Jan Dec
特殊字符串形式
簡短註釋 -- 調用 length()、sub() 或 gsub() 時,可以去掉最後一個自變量,這樣 awk 將對 $0(整個當前行)應用函數調用。要打印文件中每一行的長度,使用以下 awk 腳本:
{
print length()
}
財務上的趣事
幾星期前,我決定用 awk 編寫自己的支票簿結算程序。我決定使用簡單的 tab 定界文本文件,以便於輸入最近的存款和提款記錄。其思路是將這個數據交給 awk 腳本,該腳本會自動合計所有金額,並告訴我餘額。以下是我決定如何將所有交易記錄到 "ASCII checkbook" 中:
23 Aug 2000 food - - Y Jimmy's Buffet 30.25
此文件中的每個字段都由一個或多個 tab 分隔。在日期(字段 1,$1)之後,有兩個字段叫做「費用分類帳」和「收入分類帳」。以上面這行為例,輸入費用時,我在費用字段中放入四個字母的別名,在收入字段中放入 "-"(空白項)。這表示這一特定項是「食品費用」。 以下是存款的示例:
23 Aug 2000 - inco - Y Boss Man 2001.00
在這個實例中,我在費用分類帳中放入 "-"(空白),在收入分類帳中放入 "inco"。"inco" 是一般(薪水之類)收入的別名。使用分類帳別名讓我可以按類別生成收入和費用的明細分類帳。至於記錄的其餘部分,其它所有字段都是不需加以說明的。「是否付清?」字段("Y" 或 "N")記錄了交易是否已過帳到我的帳戶;除此之外,還有一個交易描述,和一個正的美元金額。
用於計算當前餘額的算法不太難。awk 只需要依次讀取每一行。如果列出了費用分類帳,但沒有收入分類帳(為 "-"),那麼這一項就是借方。如果列出了收入分類帳,但沒有費用分類帳(為 "-"),那麼這一項就是貸方。而且,如果同時列出了費用和收入分類帳,那麼這個金額就是「分類帳轉帳」;即,從費用分類帳減去美元金額,並將此金額添加到收入分類帳。此外,所有這些分類帳都是虛擬的,但對於跟蹤收入和支出以及預算卻非常有用。
代碼
現在該研究代碼了。我們將從第一行(BEGIN 塊和函數定義)開始:
balance,第 1 部分
#!/usr/bin/env awk -f
BEGIN {
FS="\t+"
months="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
}
function monthdigit(mymonth) {
return (index(months,mymonth)+3)/4
}
首先執行 "chmod +x myscript" 命令,那麼將第一行 "#!..." 添加到任何 awk 腳本將使它可以直接從 shell 中執行。其餘行定義了 BEGIN 塊,在 awk 開始處理支票簿文件之前將執行這個代碼塊。我們將 FS(字段分隔符)設置成 "\t+",它會告訴 awk 字段由一個或多個 tab 分隔。另外,我們定義了字符串 months,下面將出現的 monthdigit() 函數將使用它。
最後三行顯示了如何定義自己的 awk 。格式很簡單 -- 輸入 "function",再輸入名稱,然後在括號中輸入由逗號分隔的參數。在此之後,"{ }" 代碼塊包含了您希望這個函數執行的代碼。所有函數都可以訪問全局變量(如 months 變量)。另外,awk 提供了 "return" 語句,它允許函數返回一個值,並執行類似於 C 和其它語言中 "return" 的操作。這個特定函數將以 3 個字母字符串格式表示的月份名稱轉換成等價的數值。例如,以下代碼:
print monthdigit("Mar")
……將打印:
3
現在,讓我們討論其它一些函數。
財務函數
以下是其它三個執行簿記的函數。我們即將見到的主代碼塊將調用這些函數之一,按順序處理支票簿文件的每一行,從而將相應交易記錄到 awk 數組中。有三種基本交易,貸方 (doincome)、借方 (doexpense) 和轉帳 (dotransfer)。您會發現這三個函數全都接受一個自變量,叫作 mybalance。mybalance 是二維數組的一個佔位符,我們將它作為自變量進行傳遞。目前,我們還沒有處理過二維數組;但是,在下面可以看到,語法非常簡單。只須用逗號分隔每一維就行了。
我們將按以下方式將信息記錄到 "mybalance" 中。數組的第一維從 0 到 12,用於指定月份,0 代表全年。第二維是四個字母的分類帳,如 "food" 或 "inco";這是我們處理的真實分類帳。因此,要查找全年食品分類帳的餘額,應查看 mybalance[0,"food"]。要查找 6 月的收入,應查看 mybalance[6,"inco"]。
balance,第 2 部分
function doincome(mybalance) {
mybalance[curmonth,$3] += amount
mybalance[0,$3] += amount
}
function doexpense(mybalance) {
mybalance[curmonth,$2] -= amount
mybalance[0,$2] -= amount
}
function dotransfer(mybalance) {
mybalance[0,$2] -= amount
mybalance[curmonth,$2] -= amount
mybalance[0,$3] += amount
mybalance[curmonth,$3] += amount
}
調用 doincome() 或任何其它函數時,我們將交易記錄到兩個位置 -- mybalance[0,category] 和 mybalance[curmonth, category],它們分別表示全年的分類帳餘額和當月的分類帳餘額。這讓我們稍後可以輕鬆地生成年度或月度收入/支出明細分類帳。
如果研究這些函數,將發現在我的引用中傳遞了 mybalance 引用的數組。另外,我們還引用了幾個全局變量:curmonth,它保存了當前記錄所屬的月份的數值,$2(費用分類帳),$3(收入分類帳)和金額($7,美元金額)。調用 doincome() 和其它函數時,已經為要處理的當前記錄(行)正確設置了所有這些變量。
主塊
以下是主代碼塊,它包含了分析每一行輸入數據的代碼。請記住,由於正確設置了 FS,可以用 $ 1 引用第一個字段,用 $2 引用第二個字段,依次類推。調用 doincome() 和其它函數時,這些函數可以從函數內部訪問 curmonth、$2、$3 和金額的當前值。請先研究代碼,在代碼之後可以見到我的說明。
balance,第 3 部分
{
curmonth=monthdigit(substr($1,4,3))
amount=$7
#record all the categories encountered
if ( $2 != "-" )
globcat[$2]="yes"
if ( $3 != "-" )
globcat[$3]="yes"
#tally up the transaction properly
if ( $2 == "-" ) {
if ( $3 == "-" ) {
print "Error: inc and exp fields are both blank!"
exit 1
} else {
#this is income
doincome(balance)
if ( $5 == "Y" )
doincome(balance2)
}
} else if ( $3 == "-" ) {
#this is an expense
doexpense(balance)
if ( $5 == "Y" )
doexpense(balance2)
} else {
#this is a transfer
dotransfer(balance)
if ( $5 == "Y" )
dotransfer(balance2)
}
}
在主塊中,前兩行將 curmonth 設置成 1 到 12 之間的整數,並將金額設置成字段 7(使代碼易於理解)。然後,是四行有趣的代碼,它們將值寫到數組 globcat 中。globcat,或稱作全局分類帳數組,用於記錄在文件中遇到的所有分類帳 -- "inco"、"misc"、"food"、"util" 等。例如,如果 $2 == "inco",則將 globcat["inco"] 設置成 "yes"。稍後,我們可以使用簡單的 "for (x in globcat)" 循環來迭代分類帳列表。
在接著的大約二十行中,我們分析字段 $2 和 $3,並適當記錄交易。如果 $2=="-" 且 $3!="-",表示我們有收入,因此調用 doincome()。如果是相反的情況,則調用 doexpense();如果 $2 和 $3 都包含分類帳,則調用 dotransfer()。每次我們都將 "balance" 數組傳遞給這些函數,從而在這些函數中記錄適當的數據。
您還會發現幾行代碼說「if ( $5 == "Y" ),那麼將同一個交易記錄到 balance2 中」。我們在這裡究竟做了些什麼?您將回憶起 $5 包含 "Y" 或 "N",並記錄交易是否已經過帳到帳戶。由於僅當過帳了交易時我們才將交易記錄到 balance2,因此 balance2 包含了真實的帳戶餘額,而 "balance" 包含了所有交易,不管是否已經過帳。可以使用 balance2 來驗證數據項(因為它應該與當前銀行帳戶餘額匹配),可以使用 "balance" 來確保沒有透支帳戶(因為它會考慮您開出的尚未兌現的所有支票)。
生成報表
主塊重複處理了每一行記錄之後,現在我們有了關於比較全面的、按分類帳和按月份劃分的借方和貸方記錄。現在,在這種情況下最合適的做法是只須定義生成報表的 END 塊:
balance,第 4 部分
END {
bal=0
bal2=0
for (x in globcat) {
bal=bal+balance[0,x]
bal2=bal2+balance2[0,x]
}
printf("Your available funds: %10.2f\n", bal)
printf("Your account balance: %10.2f\n", bal2)
}
這個報表將打印出匯總,如下所示:
Your available funds:1174.22
Your account balance:2399.33
在 END 塊中,我們使用 "for (x in globcat)" 結構來迭代每一個分類帳,根據記錄在案的交易結算主要餘額。實際上,我們結算兩個餘額,一個是可用資金,另一個是帳戶餘額。要執行程序並處理您在文件 "mycheckbook.txt" 中輸入的財務數據,將以上所有代碼放入文本文件 "balance",執行 "chmod +x balance",然後輸入 "./balance mycheckbook.txt"。然後 balance 腳本將合計所有交易,打印出兩行餘額匯總。
電腦 Linux-awk實用技巧-01
字串處理工具: Awk
Awk 的使用例子:
# awk ‘{ print }’ /etc/passwd
以上指令將 /etc/passwd 作為 awk 的輸入檔案,並會將 /etc/passwd 檔案的內容逐行輸出。但這樣使用 awk 看不出它的作用,以下是另一個例子:
# awk -F”:” ‘{ print $1 }’ /etc/passwd
以上例子使用 awk 時加入了 -F 選項,並指定每一行用 “:” 作為分隔字串。而 print $1 的意思是印出分隔後的第一組字串。輸出結果是系統所有帳號的使用者名稱。
如果將 awk 用管線 (pipe) 和其他指令配合的話,作用會更加大,例如用 “ls -l /etc” 的話,會將/etc 的內容及其他檔案/目錄資料印出,但我不想看建立日期及檔案體積等資訊,只要看檔案/目錄及其權限,可以這樣做:
# ls -l /etc | awk ‘{print $1 “t” $9}’
因為 awk 預設會用 tab 或空白字串作為分隔,所以今次不用 -F 選擇。以上會將 “ls -l /etc” 的輸出作為 awk 的輸入內容,而會印出分隔後第一及第九組字串,兩個字串中間會用 “t” 分開。
#awk -F, 'NR==2 {print $2}' /etc/passwd
-F, 以 , 為分隔字串。
NR==2 第二列
Awk 的使用例子:
# awk ‘{ print }’ /etc/passwd
以上指令將 /etc/passwd 作為 awk 的輸入檔案,並會將 /etc/passwd 檔案的內容逐行輸出。但這樣使用 awk 看不出它的作用,以下是另一個例子:
# awk -F”:” ‘{ print $1 }’ /etc/passwd
以上例子使用 awk 時加入了 -F 選項,並指定每一行用 “:” 作為分隔字串。而 print $1 的意思是印出分隔後的第一組字串。輸出結果是系統所有帳號的使用者名稱。
如果將 awk 用管線 (pipe) 和其他指令配合的話,作用會更加大,例如用 “ls -l /etc” 的話,會將/etc 的內容及其他檔案/目錄資料印出,但我不想看建立日期及檔案體積等資訊,只要看檔案/目錄及其權限,可以這樣做:
# ls -l /etc | awk ‘{print $1 “t” $9}’
因為 awk 預設會用 tab 或空白字串作為分隔,所以今次不用 -F 選擇。以上會將 “ls -l /etc” 的輸出作為 awk 的輸入內容,而會印出分隔後第一及第九組字串,兩個字串中間會用 “t” 分開。
#awk -F, 'NR==2 {print $2}' /etc/passwd
-F, 以 , 為分隔字串。
NR==2 第二列
電腦 Linux-grep 實用技巧-01
grep 指令實用技巧
grep 常見的用法:
1. 搜索檔案內容: 以下會在 /etc/passwd 搜索 phpini 字串:
# grep phpini /etc/passwd
然後 grep 就會將 /etc/passwd 內有 phpini 字串的行印出。如果要搜索多個檔案, 只要在指令後面逐一加上檔案就會自動搜索, 例如:
# grep phpini /etc/passwd /etc/groups
如果想列出找到資料的行數, 可以加入 -n 參數:
# grep -n phpini /etc/passwd
2. 搜索目錄內容: 例如目錄內有多個檔案及目錄, 可以這樣:
# ls -l /var/www/html | grep .html
3. 排除字串: 用 -v 參數, 會印出不包含特定字串的資料, 以下會印出不包括 phpini 的資料:
# ls -v /var/www/html | grep .html
4. 搜索空白行:
# grep ^$ /etc/passwd
5. 忽略英文大小寫搜索資料
# grep -i PHPINI /etc/passwd
6. 印出總共找到的資料數量, 等同 grep phpini /etc/passwd | wc -l
# grep -C phpini /etc/passwd
grep 常見的用法:
1. 搜索檔案內容: 以下會在 /etc/passwd 搜索 phpini 字串:
# grep phpini /etc/passwd
然後 grep 就會將 /etc/passwd 內有 phpini 字串的行印出。如果要搜索多個檔案, 只要在指令後面逐一加上檔案就會自動搜索, 例如:
# grep phpini /etc/passwd /etc/groups
如果想列出找到資料的行數, 可以加入 -n 參數:
# grep -n phpini /etc/passwd
2. 搜索目錄內容: 例如目錄內有多個檔案及目錄, 可以這樣:
# ls -l /var/www/html | grep .html
3. 排除字串: 用 -v 參數, 會印出不包含特定字串的資料, 以下會印出不包括 phpini 的資料:
# ls -v /var/www/html | grep .html
4. 搜索空白行:
# grep ^$ /etc/passwd
5. 忽略英文大小寫搜索資料
# grep -i PHPINI /etc/passwd
6. 印出總共找到的資料數量, 等同 grep phpini /etc/passwd | wc -l
# grep -C phpini /etc/passwd
電腦 Linux-限制 Crontab 指令執行時間
限制 Crontab 指令執行時間
在執行 crontab 內的指令時, 如果想要限制執行時間, 可以使用 timeout 指令完成。
而這個方法不僅適用於 crontab, 即是一般指令也適用。
在 man 查看 timeout 指令的用法:
timeout – run a command with a time limit
*/5 * * * * /path/to/script.sh
以上看到 /path/to/script.sh 會每 5 分鐘執行一次, 將以上內容加上 /usr/bin/timeout,
設定為執行限時 60 秒:
*/5 * * * * /usr/bin/timeout 60 /path/to/script.sh
當 /path/to/script.sh 執行超過 60 秒時, timeout 對 script.sh 發出 kill signal
2016年11月6日 星期日
電腦 Linux 發行版與版本
查詢 Linux 發行版
ls -l /etc/*-release
cat /etc/redhat-release
cat /etc/os-release
cat /etc/lsb-release
使用 lsb_release 指令查詢
lsb_release 是一個用來查詢 Linux 發行版資訊的指令,但是並不是每一種 Linux 發行版預設都會安裝這個指令:
lsb_release -a
查詢 Linux 核心版本
uname -a
cat /proc/version
查詢 Linux 發行版與版本
ls -l /etc/*-release
cat /etc/redhat-release
cat /etc/os-release
cat /etc/lsb-release
使用 lsb_release 指令查詢
lsb_release 是一個用來查詢 Linux 發行版資訊的指令,但是並不是每一種 Linux 發行版預設都會安裝這個指令:
lsb_release -a
查詢 Linux 核心版本
uname -a
cat /proc/version
查詢 Linux 發行版與版本
2016年11月4日 星期五
CentOS 7 更改 hostname
Centos 7 以前更改 hostname 可以修改 /etc/sysconfig/network。
現在 Centos 7 只要使用 hostnamectl
檢查主機 hostname:
hostnamectl
修改hostname:
hostnamectl set-hostname hostname_new
上面的 hostname_new 是新 hostname。
現在 Centos 7 只要使用 hostnamectl
檢查主機 hostname:
hostnamectl
修改hostname:
上面的 hostname_new 是新 hostname。
2016年11月3日 星期四
Windows RDP protocol TLS1.1 Support
RDP protocol TLS1.1 Support
First apply this KB https://support.microsoft.com/en-us/kb/3080079 and reboot the machine to RDS works with TLS1.1 and TLS1.2
FOR PCI-DSS 3.1 2015:
Create a .REG file with following data and reboot de machine again. This .REG file will disable insecure hashes, cipher suites and protocols, if you like:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL]
"EventLogging"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\NULL]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 40/128]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 56/128]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 56/56]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 128/128]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 40/128]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 56/128]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 64/128]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\CipherSuites]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\MD5]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\SHA]
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
"DisabledByDefault"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
"DisabledByDefault"=dword:00000001
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client]
"DisabledByDefault"=dword:00000001
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server]
"DisabledByDefault"=dword:00000001
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client]
"DisabledByDefault"=dword:00000001
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server]
"DisabledByDefault"=dword:00000001
"Enabled"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001
Windows IIS安全性設定(powershell)
依據 Setup your IIS for SSL Perfect Forward Secrecy and TLS 1.2 提供的相關powershell指令,直接執行。
相關說明。
This PowerShell script setups your Microsoft Internet Information Server 7.5/8.0/8.5/10 (IIS) on Windows 2008R2/2012/2012R2/2016 to support TLS 1.1 and TLS 1.2 protocol with Forward secrecy. Additionally it increases security of your SSL connections by disabling insecure SSL2 and SSL3 and all insecure and weak ciphers that a browser may fall-back, too. This script implements the current best practice rules.
26.09.2016: Released v1.7. Windows Version compare failed and Get-CimInstance requires Windows 2012 or later, but the script supports Windows 2008R2 and later.
相關說明。
This PowerShell script setups your Microsoft Internet Information Server 7.5/8.0/8.5/10 (IIS) on Windows 2008R2/2012/2012R2/2016 to support TLS 1.1 and TLS 1.2 protocol with Forward secrecy. Additionally it increases security of your SSL connections by disabling insecure SSL2 and SSL3 and all insecure and weak ciphers that a browser may fall-back, too. This script implements the current best practice rules.
26.09.2016: Released v1.7. Windows Version compare failed and Get-CimInstance requires Windows 2012 or later, but the script supports Windows 2008R2 and later.
電腦 Windows regedit登錄進階設定
regedit登錄編輯的進階設定
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer
"NoDriveTypeAutoRun"=hex:b5" 取消自動播放資料光碟為"b5", 自動播放
為"95"
"NoRecentDocsMenu"=hex:1" 隱藏文件選單"
"NoLogoff"=hex:0" 隱藏開始選單的登出"
"NoFavoritesMenu"=hex:1" 隱藏我的最愛選單"
"NoRecentDocsHistory"=hex:1" 隱藏文件歷史記錄"
"NoPrinterTabs"=dword:1" 隱藏一般及詳細資料畫面"
"NoDeletePrinter"=dword:1" 關閉刪除印表機"
"NoAddPrinter"=dword:1" 關閉其它印表機"
"NoStartMenuSubFolders"=dword:1" 隱藏開始功能表子資料夾"
"NoRun"=dword:1" 移除 '執行' 指令"
"NoSetFolders"=dword:1" 從開始功能表的 '設定' 移除資料夾"
"NoSetTaskbar"=dword:1" 從開始功能表的 '設定' 移除工作列"
"NoFind"=dword:1" 移除 '尋找' 指令"
"NoDrives"=hex: 取消的磁碟機代號
"NoDrives"=dword:03ffffff" 隱藏 '我的電腦' 的磁碟機"
"NoNetHood"=dword:1" 隱藏網路上的芳鄰"
"NoDesktop"=dword:1" 隱藏桌面上所有的項目"
"NoClose"=dword:1" 關閉「關機」指令"
"NoSaveSettings"=dword:1" 結束不要儲存設定值"
"RestrictRun"=dword:00000001 "只執行容許的應用程式檔名,需配合另
一個機碼RestrictRun
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\RestrictRun
"1"="regedit.exe"
"2"="command.com"
注意,這個機碼相當的危險,可能會使電腦無法使用,所以一定要設定成
Regedit可以使用才行
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\System
顯示器
"NoDispCPL"=dword:1" 關閉顯示器控制台"
"NoDispBackgroundPage"=dword:1" 隱藏背景畫面"
"NoDispScrSavPage"=dword:1" 隱藏螢幕保護裝置畫面"
"NoDispAppearancePage"=dword:1" 隱藏外觀畫面"
"NoDispSettingsPage"=dword:1" 隱藏設定值畫面"
"NoSecCPL"=dword:1" 關閉密碼控制台"
"NoPwdPage"=dword:1" 隱藏變更密碼畫面"
"NoAdminPage"=dword:1" 隱藏遠端管理畫面"
"NoProfilePage"=dword:1" 隱藏使用者設定檔畫面"
"NoDevMgrPage"=dword:1" 隱藏裝置管理員畫面"
"NoConfigPage"=dword:1" 隱藏硬碟設定檔畫面"
"NoFileSysPage"=dword:1" 隱藏檔案系統按鈕"
"NoVirtMemPage"=dword:1" 隱藏虛擬記憶體按鈕"
"DisableRegistryTools"=dword:1" 關閉登錄編輯工具"
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\WinOldApp
"Disabled"=dword:1" 關閉 MS-DOS 模式"
"NoRealMode"=dword:1" 關閉單一模式 MS-DOS 應用程式"
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\Network
"NoNetSetup"=dword:1" 關閉網路控制台"
"NoNetSetupIDPage"=dword:1" 隱藏識別資料畫面"
"NoNetSetupSecurityPage"=dword:1" 隱藏存取控制畫面"
"NoFileSharingControl"=dword:1" 關閉檔案分享控制"
"NoPrintSharingControl"=dword:1" 關閉列印分享控制"
"NoEntireNetwork"=dword:1" 網路上的芳鄰沒有 '整個網路'"
"NoWorkgroupContents"=dword:1" 網路上的芳鄰沒有工作群組內容"
"登入旗號"
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
Winlogon]
"LegalNoticeCaption"="隨你高興"
"LegalNoticeText"="網址 E_Mail "
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
Policies\Network]
"HideSharePwds"=dword:1" 用星號隱藏資源分享密碼
"DisablePwdCaching"=dword:1" 關閉密碼快取處理
"AlphanumPwds"=dword:1" 需要英數字元的 Windows 密碼
"MinPwdLen"=dword:1" 最短的 Windows 密碼長度
"NoDialIn"=dword:1 撥號網路""關閉撥入
http://bonny.com.tw/bbs/viewthread.php?tid=1266
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer
"NoDriveTypeAutoRun"=hex:b5" 取消自動播放資料光碟為"b5", 自動播放
為"95"
"NoRecentDocsMenu"=hex:1" 隱藏文件選單"
"NoLogoff"=hex:0" 隱藏開始選單的登出"
"NoFavoritesMenu"=hex:1" 隱藏我的最愛選單"
"NoRecentDocsHistory"=hex:1" 隱藏文件歷史記錄"
"NoPrinterTabs"=dword:1" 隱藏一般及詳細資料畫面"
"NoDeletePrinter"=dword:1" 關閉刪除印表機"
"NoAddPrinter"=dword:1" 關閉其它印表機"
"NoStartMenuSubFolders"=dword:1" 隱藏開始功能表子資料夾"
"NoRun"=dword:1" 移除 '執行' 指令"
"NoSetFolders"=dword:1" 從開始功能表的 '設定' 移除資料夾"
"NoSetTaskbar"=dword:1" 從開始功能表的 '設定' 移除工作列"
"NoFind"=dword:1" 移除 '尋找' 指令"
"NoDrives"=hex: 取消的磁碟機代號
"NoDrives"=dword:03ffffff" 隱藏 '我的電腦' 的磁碟機"
"NoNetHood"=dword:1" 隱藏網路上的芳鄰"
"NoDesktop"=dword:1" 隱藏桌面上所有的項目"
"NoClose"=dword:1" 關閉「關機」指令"
"NoSaveSettings"=dword:1" 結束不要儲存設定值"
"RestrictRun"=dword:00000001 "只執行容許的應用程式檔名,需配合另
一個機碼RestrictRun
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\RestrictRun
"1"="regedit.exe"
"2"="command.com"
注意,這個機碼相當的危險,可能會使電腦無法使用,所以一定要設定成
Regedit可以使用才行
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\System
顯示器
"NoDispCPL"=dword:1" 關閉顯示器控制台"
"NoDispBackgroundPage"=dword:1" 隱藏背景畫面"
"NoDispScrSavPage"=dword:1" 隱藏螢幕保護裝置畫面"
"NoDispAppearancePage"=dword:1" 隱藏外觀畫面"
"NoDispSettingsPage"=dword:1" 隱藏設定值畫面"
"NoSecCPL"=dword:1" 關閉密碼控制台"
"NoPwdPage"=dword:1" 隱藏變更密碼畫面"
"NoAdminPage"=dword:1" 隱藏遠端管理畫面"
"NoProfilePage"=dword:1" 隱藏使用者設定檔畫面"
"NoDevMgrPage"=dword:1" 隱藏裝置管理員畫面"
"NoConfigPage"=dword:1" 隱藏硬碟設定檔畫面"
"NoFileSysPage"=dword:1" 隱藏檔案系統按鈕"
"NoVirtMemPage"=dword:1" 隱藏虛擬記憶體按鈕"
"DisableRegistryTools"=dword:1" 關閉登錄編輯工具"
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\WinOldApp
"Disabled"=dword:1" 關閉 MS-DOS 模式"
"NoRealMode"=dword:1" 關閉單一模式 MS-DOS 應用程式"
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\
Policies\Explorer\Network
"NoNetSetup"=dword:1" 關閉網路控制台"
"NoNetSetupIDPage"=dword:1" 隱藏識別資料畫面"
"NoNetSetupSecurityPage"=dword:1" 隱藏存取控制畫面"
"NoFileSharingControl"=dword:1" 關閉檔案分享控制"
"NoPrintSharingControl"=dword:1" 關閉列印分享控制"
"NoEntireNetwork"=dword:1" 網路上的芳鄰沒有 '整個網路'"
"NoWorkgroupContents"=dword:1" 網路上的芳鄰沒有工作群組內容"
"登入旗號"
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
Winlogon]
"LegalNoticeCaption"="隨你高興"
"LegalNoticeText"="網址 E_Mail "
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
Policies\Network]
"HideSharePwds"=dword:1" 用星號隱藏資源分享密碼
"DisablePwdCaching"=dword:1" 關閉密碼快取處理
"AlphanumPwds"=dword:1" 需要英數字元的 Windows 密碼
"MinPwdLen"=dword:1" 最短的 Windows 密碼長度
"NoDialIn"=dword:1 撥號網路""關閉撥入
http://bonny.com.tw/bbs/viewthread.php?tid=1266
2016年11月2日 星期三
電腦 Cacti-監控nginx狀態
1.先確認nginx編譯時包含http_stub_status_module
nginx -V
2.增加狀態設定,重啟服務
vim /etc/nginx/conf.d/default.conf
location /status/ {
stub_status on;
access_log off;
allow 192.168.1.0/24;
deny all;
}
3.下載nginx監控模板
wget http://www.oschina.net/uploads/code/cacti-nginx.tar.gz
tar xvfz cacti-nginx.tar.gz
cp cacti-nginx/get_nginx_socket_status.pl /var/www/html/cacti/scripts/
cp cacti-nginx/get_nginx_clients_status.pl /var/www/html/cacti/scripts/
4.檢測確認訊息
/var/www/html//cacti/scripts/get_nginx_clients_status.pl http://192.168.1.25/status/
/data/cacti/scripts/get_nginx_socket_status.pl http://192.168.1.25/status/
5.在cacti匯入xml
cacti_graph_template_nginx_clients_stat.xml
cacti_graph_template_nginx_sockets_stat.xml
6.在創建圖形的URL of nginx stub status,輸入監控的頁面的url,
http://192.168.1.25/status/
7.測試錯誤訊息:no (LWP::UserAgent not found),是perl裡缺少組件,
yum install perl-LWP-UserAgent-DNS-Hosts
cacti監控nginx圖解
為 Cacti 添加 Nginx status 監控
電腦-Server-Zabbix 中文顯示
Zabbix 中文顯示修正
Zabbix 修改為中文顯示後,有些圖形顯示的標籤都是口口。。。
解決方法:
從windows下控制面板->字體->選擇一種中文字庫例如“楷體”
把它拷貝到zabbix的web端的fonts目錄下例如:php/fonts,把TTF更改為ttf
修改zabbix的web端/include/defines.inc.php
define('ZBX_GRAPH_FONT_NAME', '新字體名字')
Zabbix 修改為中文顯示後,有些圖形顯示的標籤都是口口。。。
解決方法:
從windows下控制面板->字體->選擇一種中文字庫例如“楷體”
把它拷貝到zabbix的web端的fonts目錄下例如:php/fonts,把TTF更改為ttf
修改zabbix的web端/include/defines.inc.php
define('ZBX_GRAPH_FONT_NAME', '新字體名字')
電腦-Zabbix 安裝 (centos 7)
CentOS-Zabbix 安裝 (centos 7)
yum install php-php-gettext net-snmp-devel
yum install libdbi-dbd-mysql net-snmp-devel curl-devel net-snmp libcurl-devel libxml2-devel
wget http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-release-3.0-1.el7.noarch.rpm
rpm -ivh zabbix-release-3.0-1.el7.noarch.rpm
yum install zabbix-server-mysql zabbix-web-mysql
Creating initial database
Create zabbix database and user on MySQL.
shell> mysql -uroot -p<password>
mysql> create database zabbix character set utf8 collate utf8_bin;
mysql> grant all privileges on zabbix.* to zabbix@localhost identified by 'zabbix';
mysql> quit;
shell> cd database/mysql
shell> mysql -uzabbix -pzabbix zabbix < schema.sql
# stop here if you are creating database for Zabbix proxy
shell> mysql -uzabbix -pzabbix zabbix < images.sql
shell> mysql -uzabbix -pzabbix zabbix < data.sql
Then import initial schema and data.
# cd /usr/share/doc/zabbix-server-mysql-3.0.4
# zcat create.sql.gz | mysql -uroot zabbix -p
Starting Zabbix server process
Edit database configuration in zabbix_server.conf
# vim /etc/zabbix/zabbix_server.conf
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=zabbix
Start Zabbix server process.
# systemctl start zabbix-server
Editing PHP configuration for Zabbix frontend
Apache configuration file for Zabbix frontend is located in /etc/httpd/conf.d/zabbix.conf.
Some PHP settings are already configured.
php_value max_execution_time 300
php_value memory_limit 128M
php_value post_max_size 16M
php_value upload_max_filesize 2M
php_value max_input_time 300
php_value always_populate_raw_post_data -1
# php_value date.timezone Asia/Taipei
It's necessary to uncomment the “date.timezone” setting and set the right timezone for you.
After changing the configuration file restart the apache web server.
# systemctl start httpd
Zabbix frontend is available at http://zabbix-frontend-hostname/zabbix in the browser.
Default username/password is Admin/zabbix.
yum install php-php-gettext net-snmp-devel
yum install libdbi-dbd-mysql net-snmp-devel curl-devel net-snmp libcurl-devel libxml2-devel
wget http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-release-3.0-1.el7.noarch.rpm
rpm -ivh zabbix-release-3.0-1.el7.noarch.rpm
yum install zabbix-server-mysql zabbix-web-mysql
Creating initial database
Create zabbix database and user on MySQL.
shell> mysql -uroot -p<password>
mysql> create database zabbix character set utf8 collate utf8_bin;
mysql> grant all privileges on zabbix.* to zabbix@localhost identified by 'zabbix';
mysql> quit;
shell> cd database/mysql
shell> mysql -uzabbix -pzabbix zabbix < schema.sql
# stop here if you are creating database for Zabbix proxy
shell> mysql -uzabbix -pzabbix zabbix < images.sql
shell> mysql -uzabbix -pzabbix zabbix < data.sql
Then import initial schema and data.
# cd /usr/share/doc/zabbix-server-mysql-3.0.4
# zcat create.sql.gz | mysql -uroot zabbix -p
Starting Zabbix server process
Edit database configuration in zabbix_server.conf
# vim /etc/zabbix/zabbix_server.conf
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=zabbix
Start Zabbix server process.
# systemctl start zabbix-server
Editing PHP configuration for Zabbix frontend
Apache configuration file for Zabbix frontend is located in /etc/httpd/conf.d/zabbix.conf.
Some PHP settings are already configured.
php_value max_execution_time 300
php_value memory_limit 128M
php_value post_max_size 16M
php_value upload_max_filesize 2M
php_value max_input_time 300
php_value always_populate_raw_post_data -1
# php_value date.timezone Asia/Taipei
It's necessary to uncomment the “date.timezone” setting and set the right timezone for you.
After changing the configuration file restart the apache web server.
# systemctl start httpd
Zabbix frontend is available at http://zabbix-frontend-hostname/zabbix in the browser.
Default username/password is Admin/zabbix.
電腦 fortigate firewall 重啟服務
ssh登入 firewall
FGT110C (global) # fnsysctl ls /var/run/snmpd.pid
/var/run/snmpd.pid
FGT110C (global) # fnsysctl cat /var/run/snmpd.pid
123(pid)
then kill the proc using diag sys kill or fnsysctl kill -9 <pid>
To Restart the Daemon type:
diag test application snmpd 99
Restart SNMP service
How to kill the dhcp daemon or any daemons on a fortigate appliance
2016年11月1日 星期二
Linux find-找出空目錄並刪除
利用 find 指令,有兩個參數可用,分別是 -depth 與 -empty。
可以加上 -type d 只找目錄,不加的話,會連空檔案都找出來。
find . -depth -empty -type d
不含子目錄
find . -maxdepth 1 -empty -type d
配合 -exec 就可以全部刪掉。
find . -depth -empty -type d -exec rmdir -v {} \;
參考網址:
[Linux]找出某個目錄底下的空目錄並刪除之
在 Linux 上找出空目錄, 而且刪掉它
Linux-find 指令使用範例-02
Linux-find 指令使用範例教學-02
find 有一系列時間相關的參數:
-mtime n
指定檔案的最後修改時間(modification time),單位為天。
-mmin n
指定檔案的最後修改時間,單位為分鐘。
-atime n
指定檔案的最後存取時間(access time),單位為天。
-amin n
指定檔案的最後存取
指定檔案狀態相關資訊最後修改的時間(status time),單位為天。
-cmin n
指定檔案狀態相關資訊最後修改的時間,單位為分鐘。
找尋剛好在 7 天之前有被修改過的檔案(例如今天是 9/17,那麼 7 天前就是 9/11):
find . -mtime 7
找尋最近 7 天之內有被修改過的檔案(例如今天是 9/17,那麼 7 天之內就是 9/11 到 9/17):
find . -mtime -7
找尋上次修改的時間是在 7 天以上的檔案(例如今天是 9/17,那麼修改時間在 7 天以上的檔案就是 9/11 以前修改過的檔案):
find . -mtime +7
找出上次修改的時間是在 7 天以上、14 天以下的檔案:
find . -mtime +7 -mtime -14
找尋最近一小時內更改過的檔案:
find . -mmin -60
基本上 mtime、ctime 與 atime 的時間指定方式都相同,例如找尋最近一小時內更改過狀態的檔案:
find . -cmin -60
找尋最近一小時內有被存取過的檔案:
find . -amin -60
關於 mtime、ctime 與 atime 的差異,可以參考鳥哥的文件。
參考網址:
https://blog.gtwang.org/linux/unix-linux-find-command-examples/
http://uiop7890.pixnet.net/blog/post/25865820-%5B%E8%BD%89%E8%B2%BC%5D-find-%E6%8C%87%E4%BB%A4%E6%95%99%E5%AD%B8
Linux-find 指令使用範例-00
找出7天前的目錄 ,移動至tmp
find . -mtime +7 -type d -exec mv -v {} tmp \;
計算本目錄目錄數量(不含子目錄)
find . -maxdepth 1 -type d |wc -l
計算目錄下的目錄數量(含子目錄)
find . -type d |wc -l
計算目錄下的檔案數
find ./ -type f |wc -l
計算目錄下某副檔名的檔案數
find ./ -type f -name *.inbox | wc -l
find . -mtime +7 -type d -exec mv -v {} tmp \;
計算本目錄目錄數量(不含子目錄)
find . -maxdepth 1 -type d |wc -l
計算目錄下的目錄數量(含子目錄)
find . -type d |wc -l
計算目錄下的檔案數
find ./ -type f |wc -l
計算目錄下某副檔名的檔案數
find ./ -type f -name *.inbox | wc -l
Linux SWAP動態調整
Linux SWAP動態調整
Linux OS ( RedHat/Rocky/Debian/Ubuntu ) 直接使用檔案建立SWAP,方便依需求自行調整容量。
建立方式
1. dd if=/dev/zero of=/swap.img bs=1024 count=4096000
使用4G的容量
2. mkswap /swap.img
格式化swapfile
3. swapon /swap.img
啟動swapfile
檢查確認,可使用free、swapon -s、cat /proc/swaps、top等指令
檢查確認,可使用free、swapon -s、cat /proc/swaps、top等指令
4. vim /etc/fstab
/swap.img swap swap defaults 0 0
重開機,則可自動掛載swapfile
swapon -a 可直接掛載,不需重開機。
swapon -a 可直接掛載,不需重開機。
Linux 使用tmpfs (RAM disk)
基本安裝CentOS,已經開啟tmpfs。
tmpfs容量使用本機記憶體,如果記憶體用完,會用swap空間。設定tmpfs容量,別超過記憶體。
將記憶體掛載成磁碟之後,把它當成磁碟一般存取。
記憶體存取,速度比硬碟要快,但是關機後,裡面的資料也就消失。
建立512mb /tmp的tmpfs
用 mount 指令暫時性的掛載
mount -t tmpfs -o size=512m tmpfs /tmp
修改 /etc/fstab 永久性的掛載
tmpfs /tmp tmpfs rw,relatime,size=512m 0 0
不重新開機,直接掛載
mount –a
[Linux] 在 CentOS 7 上建立 RAM disk
如何在RHEL/CentOS 7.0中使用tmpfs
Using tmpfs for /tmp
ramdisk、ramfs、tmpfs設定使用
Centos 修改 swap 與 tmpfs 大小