`
su1216
  • 浏览: 670934 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
深入入门正则表达式(jav...
浏览量:71915
E60283d7-4822-3dfb-9de4-f2377e30189c
android手机的安全问...
浏览量:128760
社区版块
存档分类
最新评论

《Unix & Linux 大学教程》 - 第十六、十七章 学习笔记

阅读更多

学习笔记,内容基础,适合初学者。

 

阅读之前,请务必花30秒查看前言说明(在第一、二章前面部分)

《Unix & Linux 大学教程》 - 第一、二章 学习笔记    Unix简介 & 什么是Linux?什么是Unix

《Unix & Linux 大学教程》 - 第三、四章 学习笔记    Unix连接 & 开始使用Unix

《Unix & Linux 大学教程》 - 第五、六章 学习笔记    GUI:图形用户界面 & Unix工作环境

《Unix & Linux 大学教程》 - 第七、八章 学习笔记    Unix键盘使用 & 能够立即使用的程序

《Unix & Linux 大学教程》 - 第九、十章 学习笔记    文档资料:Unix手册与Info & 命令语法

《Unix & Linux 大学教程》 - 第十一、十二章 学习笔记    shell & 使用shell:变量和选项

《Unix & Linux 大学教程》 - 第十三章 学习笔记    使用shell:命令和定制

《Unix & Linux 大学教程》 - 第十四、十五章 学习笔记     使用shell:初始化文件

《Unix & Linux 大学教程》 - 第十八章 学习笔记    过滤器:统计和格式化
《Unix & Linux 大学教程》 - 第十九章(一) 学习笔记    过滤器:选取、排序、组合及变换
《Unix & Linux 大学教程》 - 第十九章(二)、第二十章 学习笔记  过滤器:选取、排序、组合及变换 正则表达式

《Unix & Linux 大学教程》 - 第二十一章 学习笔记  显示文件

《Unix & Linux 大学教程》 - 第二十二章(一) 学习笔记  vi文本编辑器(一)

《Unix & Linux 大学教程》 - 第二十二章(二) 学习笔记  vi文本编辑器 (二)

《Unix & Linux 大学教程》 - 第二十二章(三) 学习笔记  vi文本编辑器 (三)

《Unix & Linux 大学教程》 - 第二十四章 学习笔记  目录操作

《Unix & Linux 大学教程》 - 第二十五章 学习笔记  文件操作

《Unix & Linux 大学教程》 - 第二十六章(一) 学习笔记  进程和作业控制

《Unix & Linux 大学教程》 - 第二十六章(二) 学习笔记  进程和作业控制

《Unix & Linux 大学教程》 - 附录F 时区与24小时制时间


第十六章:过滤器:简介和基本操作

 

 

基础知识:

cat(catenate,to join in a chain)

每次一行从标准输入读取数据,完成处理后将结果每次一行的写到标准输出。

执行cat后,控制台等待输入,按下return时,之前键入的一行发送到cat,然后cat再输出,所以在屏幕上面可以看到两行相同内容的输出。

作用

在管道中不需要使用

在I/O重定向中应用较多

cat > data

将标准输出重定向到data,可以快速建立文件。当然也可以追加到文件(>>)。

cat < data

将data作为cat的标准输入,输出到屏幕上。这里重定向符号可以省略(cat data)。cat没有翻页功能,当文件内容较多的时候,只显示文件最后的内容。

cat < data > newdata

可以利用cat 复制文件。

cat [file...]

可以利用cat从多个文件读取收集数据(大多数过滤器都允许指定多个文件名作为参数)。

 

不要将输出重定向到一个文件上

cat name address > name

上面的命令无法完成任务!原因在于shell处理重定向的方式。在冲虚将标准输出重定向到文件之前,shell必须确保这个文件存在并且是空的,如果不存在,shell将其创建;如果存在,shell将其清空。

首先name被清空,然后address输出到name中, 和cat address > name的结果是一样的,shell会给出提示:

cat: name: input file is output file

但是这时name已经被清空了!

可以改用cat address >> name

 

cat [-bns] [file...]

-n(number):在每行前面加一个行号

-b(blank):和-n一起使用,告诉cat不要对空白行编号

-s(squeeze):将多个连续空白行替换为一个空白行

 

书中一个cat应用总结,都是上面将过的内容,而且有些还是重复的。

语法 作用
cat > file 从键盘读取数据,创建新文件或者替换已有文件
cat >> file 从键盘读取数据,将数据追加到已有文件中
cat < file 显示一个已有文件
cat file 显示一个已有文件
cat <file1 > file2 复制文件
cat file1 file2 file3 | less 组合多个文件,每次一屏的显示结果。
cat file1 file2 file3 > file4 组合多个文件,将输出保存到一个不同文件中
cat file1 file2 file3 | program 组合多个文件,将输出管道出送给另一个程序

 

split

语法

split [-d] [-a num] [-l lines] [file [prefix]]

num是创建文件名时用作文件名后缀的字符或者数字数量

lines是每个新文件所包含行的最大数量

file是输入文件的名称

prefix是创建文件时使用的名称

 

split默认创建1000行数据的文件

split data(将data分割为若干个每个含1000行数据的文件)

split -l 5000 data(将data分割为若干个每个含5000行数据的文件)

 

split默认以字母x开头,类似于

xaa  xab  xac  xad  xae  xaf  xag  xah  xai

如果之前有同名文件,则被覆盖。

 

split -d -l 5000 data

改用数字做后缀

x00 x01 x02 x03 ......

 

split -d -l 5000 data y

修改文件名前缀

y00 y01 y02 y03 ......

 

split -a 3 data

split -d -a 3 data

设置文件名后缀长度

xaaa xaab xaac xaad ......

x001 x002 x003 x004 ......

 

tac

语法

tac [file...]

tac将文本写入标准输出之前,将文本行的顺序反转(第一行成为最后一行,第二行成为倒数第二行……)。

tac log > reverse-log

将log文件行反转之后输出到reverse-log中。

 

rev

语法

rev [file...]

 

反转字符顺序

rev data | tac

即反转了行,也反转了每行的字符。

 

head、tail

语法

head [-n lines] [file...]

tail [-n lines] [file...]

head从数据的开头许选择数据行

tail从数据的结尾选择数据行

head、tail默认选取10行数据

cat data1 data2 | sort | tail -n 300 | less

cat data1 data2 | sort | head > newdata

其中n可以省略,变为

tail -15 file

 

查看不断增长的文件

语法

tail -f [-n [+]lines] [file...]

(需要按下^C后tail才会停止,否则一直等到file的新输出)

 

colrm(column remove)

语法

colrm [startcol [endcol]]

程序从标准输入读取数据,删除指定的数据列,然后将剩余数据写入标准输出。

其中startcol和endcol指定要移除奇遇的开头和末尾。列的编号从1开始。

比如,我的一个文件名为text的文本文件中有如下两行数据:

1234567

abcdefg

那么我想删除第3-5列

cat text | colrm 3 5

结果为(当然,上面的命令没有改变text文件本身)

1267

abfg

注意:列的编号从1开始,并且是闭区间,而非半开半闭。

 

 

 

 

第十七章:过滤器:比较和抽取

基础知识:

重要的文件比较程序和排序文件以及从文件中选取数据的相关程序

过滤器 作用 章号 文件类型 文件数量
cmp 比较两个文件 17 二进制或者文本 2个
comm 比较两个有序文件,显示区别 17 文本:有序 2个
diff 比较两个文件,显示区别 17 文本 2个
sdiff 比较两个文件,显示区别 17 文本 2个
cut 从数据中抽取指定列(字段) 17 文本 1个或多个
paste 组合数据列 17 文本 1个或多个
sort 排序数据 19 文本 1个或多个
uniq 选取重复/唯一行 19 文本 1个
grep 选取包含指定模式的行 19 文本 个或多个
look 选取以指定模式开头的行 19 文本:有序 1个

 

cmp

语法

cmp file1 file2

逐字节的比较,如果相同,则无任何输出,否则会看到如下类似提示:

file1 file2 differ: byte 4, line 1

无须关心文件类型

 

comm

语法

comm [-123file1 file2

按行比较两个有序文件,并显示区别。

该程序以3列显示输出:

第一列:包含只在第一个文件中有的行

第二列:包含只在第二个文件中有的行

第三列:包含两个文件都有的行

 

diff

语法

diff [-bBiqswy] [-c|-Clines|-u|-Ulines] file1 file2

lines是说明上下文关系的行号

diff输出使用3个不同的单字符指示:

c(change):改变

d(delete):删除

a(append):追加

每个字符左右都会有一串行号,左边的数字指第一个文件中的行,右边的数字指第二个文件中的行。

第一个文件中的行由“<”(小于号)字符标记;第二个文件中的行由一个“>”(大于号)字符标记。两组行被由若干个连字符构成的直线分隔。

我们来比较一下android4.0和android4.1的package/app下有神马变化

ls -1 /media/dfaf020c-d352-4c0d-ba00-71a419011550/android4.0/packages/apps > android40

ls -1 /media/dfaf020c-d352-4c0d-ba00-71a419011550/android4.1/packages/apps > android41

将packages/apps下的文件列表写到文件中,每行一个文件

然后比较一下这两个文件

 

diff android41 android40

log如下:

18d17
< LegacyCamera
18d17是说如果第一个文件这样做,那么就能和第二个文件相同。
那么18d17是神马意思,d表示删除,在第一个文件中删除第18行,那么就和第二个文件相同了(17可以省略,表示在第二个文件中第17行后发现了区别)

 

下面再用同样的方法看看4.0和4.1中Camera下的文件列表区别:

ls -1 /media/dfaf020c-d352-4c0d-ba00-71a419011550/android4.1/packages/apps/Camera > android41

cat android41 写道
jni
MODULE_LICENSE_APACHE2
NOTICE
perftests
res
src
tests

ls -1 /media/dfaf020c-d352-4c0d-ba00-71a419011550/android4.0/packages/apps/Camera > android40

cat android40 写道
AndroidManifest.xml
Android.mk
CleanSpec.mk
jni
MODULE_LICENSE_APACHE2
NOTICE
proguard.flags
res
src
tests

diff android41 android40

log 写道
0a1,3
> AndroidManifest.xml
> Android.mk
> CleanSpec.mk
4c7
< perftests
---
> proguard.flags

将第一个文件(android41)的第0行插入第二个文件(android40)的1-3行

将第一个文件(android41)的第4行(perftests)改为第二个文件(android40)的第七行(proguard.flags)

 

-i:忽略大小写的区别

-w:忽略所有空白字符(xx和x   x认为是一样的)

-b:忽略空白字符数量上的区别(x x和x   x认为是一样的,但xx和x   x认为是不一样的)

-B(blank lines,空白行):忽略所有空白行

-q(quiet,静止):当两个文件不同时,省略所有细节(和cmp相同,但是只能比较文本)。

-s(same,相同):当两个文件相同时,显示结果。内容大概如下

Files file1 and file2 are identical

 

-c(context,上下文):不再简洁,易理解

diff -c android41 android40 写道
*** android41 2012-08-20 15:18:05.735840338 +0800
--- android40 2012-08-20 15:18:15.265840419 +0800
***************
*** 1,7 ****
jni
MODULE_LICENSE_APACHE2
NOTICE
! perftests
res
src
tests
--- 1,10 ----
+ AndroidManifest.xml
+ Android.mk
+ CleanSpec.mk
jni
MODULE_LICENSE_APACHE2
NOTICE
! proguard.flags
res
src
tests

输出的前两行是两个文件的信息

然后是每个文件的摘录

第一个文件的1-7行,第4行需要修改

第二个文件的1-10行,第一个文件需要插入第二个文件的1-3行,第四行需要修改为第七行

(diff -C5 file1 file2,改变显示上下文的行数)

 

-u(unified output,统一输出):类似-c,但是没有重复行

diff -u android41 android40 写道
--- android41 2012-08-20 15:18:05.735840338 +0800
+++ android40 2012-08-20 15:18:15.265840419 +0800
@@ -1,7 +1,10 @@
+AndroidManifest.xml
+Android.mk
+CleanSpec.mk
jni
MODULE_LICENSE_APACHE2
NOTICE
-perftests
+proguard.flags
res
src
tests

(diff -U5 file1 file2,改变显示上下文的行数)

 

-y:两个文件行并排显示(可以使用sdiff)

diff -y file1 file2 同 sdiff file1 file2

 

sdiff

语法

sdiff [-bBilsW] [-w columnsfile1 file2

-l:当两个文件拥有共同行时,只显示左边的列

-s(same,相同):不显示在两个文件中相同的任何行

-i:忽略大小写的区别

-w:改变列的宽度

-W:忽略所有空白字符(diff使用-w

-b:忽略空白字符数量上的区别(x x和x   x认为是一样的,但xx和x   x认为是不一样的)

-B(blank lines,空白行):忽略所有空白行

 

 

cut

语法

cut -c list [file...]:抽取数据列

list是要抽取列的列表

file是输入文件的名称

ls -l 写道
total 128
-rw-r--r-- 1 su1216 su1216 107 2012-08-20 15:18 android40
-rw-r--r-- 1 su1216 su1216 58 2012-08-20 15:18 android41
-rw-r--r-- 1 su1216 su1216 108294 2012-08-06 09:54 hs_err_pid2095.log
-rw-r--r-- 1 su1216 su1216 16 2012-08-20 13:25 text
-rw-r--r-- 1 su1216 su1216 19 2012-08-20 14:10 x0000
-rw-r--r-- 1 su1216 su1216 17 2012-08-20 14:08 x0001

下面提取权限和日期部分

ls -l | cut -c 1-10,35-50

log 写道
total 128
-rw-r--r--2012-08-20 15:18
-rw-r--r--2012-08-20 15:18
-rw-r--r--2012-08-06 09:54
-rw-r--r--2012-08-20 13:25
-rw-r--r--2012-08-20 14:10
-rw-r--r--2012-08-20 14:08

 ls -l | cut -c1-10,35-50(-c和后面数字之间的空格可以省略)

 

 

cut -f list [-d delimiter] [-s] [file...]从文件行中抽取字段

list是要抽取字段的列表

delimiter是分隔字段所使用的定界符(delimiter

file是输入文件的名称

-s(suppress,抑制):遇到不包含任何定界符的行,使用此选项可以抛弃这样的行。

 

以/etc/passwd这个文件为例,下面截取一部分这个文件的内容:

cat /etc/passwd 写道
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh

cut -f 1 3-5 -d ':' /etc/passwd

我们提取每行的1,3,4,5个字段,其中冒号作为定界符。

 写道
root:0:0:root
daemon:1:1:daemon
bin:2:2:bin
sys:3:3:sys
sync:4:65534:sync
games:5:60:games
man:6:12:man
lp:7:7:lp
mail:8:8:mail
news:9:9:news

paste

语法

paste [-d char...] [file...]

char作为分隔符

file是输入文件的名称

paste可以将几个文件(每个文件都包含一列数据)组成一个大表。也可以将连续的数据行组合起来,构建多个列。

paste和cat有点相似,paste水平组合数据,cat竖直组合数据。

下面我们先把/etc/passwd拆分掉,我们就取前四列

cut -f 1 -d ':' /etc/passwd > /home/su1216/linux_test/c1

cut -f 2 -d ':' /etc/passwd > /home/su1216/linux_test/c2

cut -f 3 -d ':' /etc/passwd > /home/su1216/linux_test/c3

cut -f 4 -d ':' /etc/passwd > /home/su1216/linux_test/c4

然后我们再把它们拼到一起

paste /home/su1216/linux_test/c1 /home/su1216/linux_test/c2 /home/su1216/linux_test/c3 /home/su1216/linux_test/c4 > /home/su1216/linux_test/c

上面截取了部分结果,同之前的passwd文件基本一致,因为没有加分隔符

每列的之间放置了一个制表符(默认),Unix假设制表符为每8个位置一个,且以位置1为起点。

指定冒号为分隔符

paste -d ':' /home/su1216/linux_test/c1 /home/su1216/linux_test/c2 /home/su1216/linux_test/c3 /home/su1216/linux_test/c4 > /home/su1216/linux_test/c

也可以指定多个分隔符,当有多个分隔符时,paste交替使用分隔符。

paste -d '|&' /home/su1216/linux_test/c1 /home/su1216/linux_test/c2 /home/su1216/linux_test/c3 /home/su1216/linux_test/c4 > /home/su1216/linux_test/c

结果如下

 

名词解释:

version control system:版本控制系统

source code control system(SCCS):代码控制系统

revision control system(RCS):修订控制系统

comma-separated value(CSV):逗号分隔值

 

一些有用的过滤器

过滤器 章号 参阅 作用
awk -- perl 编程语言:操作文本
cat 16 split、tac、rev 组合文件:复制标准输入到标准输出
colrm 16 cut、join、paste 删除指定的数据列
comm 17 cmp、diff、sdiff 比较两个有序文件,显示区别
cmp 17 comm、diff、sdiff 比较两个文件
cut 17 colrm、join、paste 从数据中抽取指定列(字段)
diff 17 cmp、comm、sdiff 比较两个文件,显示不同
expand 18 unexpand 将制表符转为空格
fold 18 fmt、pr 将长行格式化成较短的行
fmt 18 fold、pr 格式化段落,从而使它们看上去更漂亮
grep 19 look、strings 选择包含指定模式的行
head 16 tail 从数据的开头选择行
join 19

colrm、cut、paste

基于公用字段,组合数据列
look 19 grep 选择以指定模式开头的行
nl 18 wc 创建行号
paste 17 colrm、cut、join 组合数据列
perl -- awk 编程语言:操作文本,文件,进程
pr 18 fold,fmt 将文本格式化为页或者列
rev 16 cat、tac 每行数据中的字符反序排列
sdiff 17 cmp、comm、diff 比较两个文件,显示区别
sed 19 tr 非交互式文本编辑
sort 19 tsort、uniq 排序数据:检查数据是否有序
split 16 cat 将大文件分隔成较小的文件
strings 19 grep 在二进制文件中搜索字符串
tac 16 cat、rev 组合文件,同时将文本行的顺序反转
tail 16 head 从数据的末尾选择行
tr 19 sed 改变或者删除选定的字符
tsort 19 sort 根据偏序创建全序
unexpand 18 expand 将空格转变成制表符
uniq 19 sort 选择重复/唯一行
wc 18 nl 统计行数、单词数和字符数

 

 

 

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

  • 大小: 16.6 KB
  • 大小: 14.6 KB
1
4
分享到:
评论

相关推荐

    linux学习笔记.docx

    Linux是一种免费使用和自由传播的类UNIX计算机操作系统的内核,其源代码可以免费获得。它诞生于1991年,由芬兰赫尔辛基大学的学生Linus Torvalds首次发布,并逐渐发展成为当今最流行的操作系统之一。Linux不仅广泛...

    Linux学习笔记.pdf,linux详解,LINUX

    本资料“Linux学习笔记.pdf”将带你深入理解Linux的基础知识和高级应用。 一、Linux系统概述 1. Linux的起源:Linux的诞生源于托瓦兹对Minix系统的不满,他决定创建一个符合个人需求的、免费的Unix-like操作系统...

    linux学习笔记 .doc

    Linux学习笔记概述 Linux是一种自由和开放源代码的操作系统,其设计目标是提供一个轻量级、高效且安全的计算平台。Linux系统采用类UNIX目录结构,每个目录都有特定的功能和用途。以下是对Linux主要目录及其内容的...

    linux系统学习笔记

    ### Linux系统学习笔记 #### 一、Linux系统Shell介绍 1. **Linux系统Shell类型**:Linux系统提供了多种Shell供用户选择,常见的包括Bourne shell (`sh`), C shell (`csh`), Korn shell (`ksh`)等。其中,`sh`是Unix...

    Ubuntu Linux实用学习笔记.doc

    ### Ubuntu Linux 实用学习笔记知识点概览 #### 一、Ubuntu简介 - **定义与适用范围**:Ubuntu是一款广泛使用的开源操作系统,适用于个人电脑、服务器和云计算环境。它基于Debian GNU/Linux,提供了丰富的应用程序...

    2009 达内Unix学习笔记

    集合了 所有的 Unix命令大全 登陆服务器时输入 公帐号 openlab-open123 telnet 192.168.0.23 自己帐号 sd08077-you0 ftp工具 192.168.0.202 tools-toolss 老师测评网址 http://172.16.0.198:8080/poll/ 各个 ...

    linux与unix经典编程

    - 第一部分的第二个至第十个字符分为三个三元组(triplet),分别表示文件属主、组用户和其他用户的权限。 - 第二部分表示文件的硬链接数目。 - 第三部分表示文件属主。 - 第四部分表示文件属主所在的默认组。 - 第...

    APUE读书笔记(Unix高级环境编程)

    - **Unix手册页**:介绍如何使用`man`命令查询Unix/Linux系统中的命令、函数等的文档,是学习Unix编程的重要资料来源。 - **系统调用与库函数**:系统调用是应用程序与操作系统内核之间的接口,库函数则是对系统调用...

    嵌入式Linux入门笔记

    通过“嵌入式Linux入门笔记”,学习者将能了解嵌入式系统的基础概念,熟悉Linux内核、设备驱动、Bootloader的工作原理,掌握构建和调试嵌入式系统的技能,为成为一名合格的嵌入式Linux开发者打下坚实基础。

    第11章 Linux操作系统基础-教程与笔记习题

    以下是对"第11章 Linux操作系统基础"的主要知识点的详细阐述。 一、Linux操作系统简介 Linux是基于Unix的操作系统,由林纳斯·托瓦兹于1991年创建。它的内核是开源的,允许全球开发者对其进行修改和优化。Linux系统...

    循序渐进Linux.

    ### 循序渐进Linux:运维架构师之旅 #### 第一章:服务器硬件的那些事儿 ##### 计算机的组成及分类 ...同时,简要概述了操作系统尤其是Unix系统的历史背景和发展现状,为进一步学习Linux操作系统奠定了基础。

    Linux全攻略第一章目录认识

    本章主要探讨的是"Linux全攻略第一章:目录认识",这对于初学者来说是一份非常实用的学习资料。Linux的目录结构是其核心组成部分,理解它对于高效地操作和管理Linux系统至关重要。 Linux基于Unix系统,采用的是单一...

    计算机基础学习笔记.pdf

    计算机基础学习笔记涵盖了计算机硬件、软件、操作系统、网络和计算机历史等多个方面。 首先,笔记提到了CPU(中央处理单元)的发展史。从ENIAC(电子数值积分计算机)作为早期的电子计算机,到Intel系列处理器的...

    基于C语言的学习笔记(附代码)

    【基于C语言的学习笔记(附代码)】 C语言是一种强大的、高效的编程语言,广泛应用于操作系统、嵌入式系统以及各种软件开发。这份学习笔记涵盖了C语言的基础、高级、系统和工具四个部分,旨在帮助读者全面理解和...

    总结搜集的shell脚本学习笔记(完结篇).pdf

    ### Shell脚本编程知识点概述 #### 一、预备知识与基本概念 在开始Shell脚本文档的学习之前,首先需要理解Shell...以上就是文档《总结搜集的shell脚本学习笔记(完结篇)》中所涵盖的主要知识点,希望对你有所帮助。

    Linux笔记[整理].pdf

    Linux操作系统是开源的类Unix系统,广泛应用于服务器、嵌入式设备和桌面环境中。了解Linux的基础知识,特别是其目录结构和命令行操作,对于软件开发人员来说至关重要。 首先,让我们来详细了解一下Linux的目录结构...

    Linux 101考试模块化培训笔记(Andrew McGill)Linux 101 Examination Modular Training Notes (Andrew McGill)

    Linux 101考试模块化培训笔记是为Linux专业人士协会(LPI)的LPI 101考试准备的,尤其针对考试的第2版目标。这本培训笔记由Andrew McGill编写,属于Leading Edge Business Solutions公司的Linux培训计划的一部分。该...

    网络三级考试笔试笔记教材

    - 操作系统:Windows、UNIX、Linux等。 3. **计算机技术指标**: - **位数**:指寄存器的字长,如8位、16位、32位、64位等。 - **速度**:通常以主频衡量CPU的运算速度。 - **容量**:包括内存和外存,常用单位...

Global site tag (gtag.js) - Google Analytics