【BASH】回顾与知识点梳理(十二)

该系列目录 --> 【BASH】回顾与知识点梳理(目录)

有小伙伴私信说,鸟哥《私房菜》的第六章也有很多命令,笔者看了下确实是这样,包括很多文件和目录相关的命令,毕竟linux一切皆文件,还是有必要进行梳理的,所以本章和下章都将从鸟哥《私房菜》的第六章摘取内容

十二. Linux 文件与目录管理

在这个章节当中,我们就直接来进一步的操作与管理文件及目录吧!包括在不同的目录间变换、 建立与删除目录、建立与删除文件,还有寻找文件、查阅文件内容等等,都会在这个章节作个简单的介绍啊!

12.1 目录与路径

相对路径与绝对路径

在开始目录的切换之前,你必须要先了解一下所谓的『路径(PATH)』, 有趣的是:什么是『相对路径』与『绝对路径』?

  • 绝对路径:路径的写法『一定由根目录 / 写起』,例如: /usr/share/doc 这个目录。
  • 相对路径:路径的写法『不是由 / 写起』,例如由 /usr/share/doc 要到 /usr/share/man 底下时,可以写成:『cd …/man』这就是相对路径的写法啦!相对路径意指『相对于目前工作目录的路径!』
相对路径的用途

那么相对路径与绝对路径有什么了不起呀?喝!那可真的是了不起了!假设你写了一个软件, 这个软件共需要三个目录,分别是 etc, bin, man 这三个目录,然而由于不同的人喜欢安装在不同的目录之下,假设甲安装的目录是 /usr/local/packages/etc, /usr/local/packages/bin 及 /usr/local/packages/man ,不过乙却喜欢安装在 /home/packages/etc, /home/packages/bin, /home/packages/man 这三个目录中,请问如果需要用到绝对路径的话,那么是否很麻烦呢?是的! 如此一来每个目录下的东西就很难对应的起来!这个时候相对路径的写法就显的特别的重要了!

此外,如果你跟鸟哥一样,喜欢将路径的名字写的很长,好让自己知道那个目录是在干什么的,例如:/cluster/raid/output/taiwan2006/smoke 这个目录,而另一个目录在 /cluster/raid/output/taiwan2006/cctm ,那么我从第一个要到第二个目录去的话,怎么写比较方便? 当然是『 cd …/cctm 』比较方便啰!对吧!

绝对路径的用途

但是对于档名的正确性来说,『绝对路径的正确度要比较好~』。 一般来说,鸟哥会建议你,如果是在写程序 (shell scripts) 来管理系统的条件下,务必使用绝对路径的写法。 怎么说呢?因为绝对路径的写法虽然比较麻烦,但是可以肯定这个写法绝对不会有问题。 如果使用相对路径在程序当中,则可能由于你执行的工作环境不同,导致一些问题的发生。

12.2 目录的相关操作

我们之前稍微提到变换目录的指令是 cd,还有哪些可以进行目录操作的指令呢? 例如建立目录啊、删除目录之类的~还有,得要先知道的,就是有哪些比较特殊的目录呢? 举例来说,底下这些就是比较特殊的目录,得要用力的记下来才行:

. 代表此层目录
.. 代表上一层目录
- 代表前一个工作目录
~ 代表『目前用户身份』所在的家目录
~account 代表 account 这个用户的家目录(account 是个账号名称)

需要特别注意的是:在所有目录底下都会存在的两个目录,分别是『.』与『..』 分别代表此层与上层目录的意思。

那么来思考一下底下这个例题:我们知道所有目录都是从根目录开始的,那么请问在 Linux 底下,根目录(/)下有没有上层目录(..)存在?

答:
若使用『 ls -al / 』去查询,可以看到根目录下确实存在 ...两个目录,再仔细的查阅, 可发现这两个目录的属性与权限完全一致,这代表根目录的上一层(..)与根目录自己(.)是同一个目录。

底下我们就来谈一谈几个常见的处理目录的指令吧:

  • cd:变换目录
  • pwd:显示当前目录
  • mkdir:建立一个新的目录
  • rmdir:删除一个空的目录
cd (change directory, 变换目录)
[dmtsai@study ~]$ su - # 先切换身份成为 root 看看!
[root@study ~]# cd [相对路径或绝对路径]
# 最重要的就是目录的绝对路径与相对路径,还有一些特殊目录的符号啰!
[root@study ~]# cd ~dmtsai
# 代表去到 dmtsai 这个用户的家目录,亦即 /home/dmtsai
[root@study dmtsai]# cd ~
# 表示回到自己的家目录,亦即是 /root 这个目录
[root@study ~]# cd
# 没有加上任何路径,也还是代表回到自己家目录的意思喔!
[root@study ~]# cd ..
# 表示去到目前的上层目录,亦即是 /root 的上层目录的意思;
[root@study /]# cd -
# 表示回到刚刚的那个目录,也就是 /root 啰~
[root@study ~]# cd /var/spool/mail
# 这个就是绝对路径的写法!直接指定要去的完整路径名称!
[root@study mail]# cd ../postfix
# 这个是相对路径的写法,我们由/var/spool/mail 去到/var/spool/postfix 就这样写!

我们的提示字符,亦即那个 [root@study ~]# 当中,就已经有指出当前目录了, 刚登入时会到自己的家目录,而家目录还有一个代码,那就是『 ~ 』符号! 例如上面的例子可以发现,使用『 cd ~ 』可以回到个人的家目录里头去呢! 另外,针对 cd 的使用方法,如果仅输入 cd 时,代表的就是『 cd ~ 』的意思喔~ 亦即是会回到自己的家目录啦!而那个『 cd - 』比较难以理解,请自行多做几次练习,就会比较明白了。

pwd (Print Working Directory, 显示目前所在的目录)
[root@study ~]# pwd [-P]
选项与参数:
-P :显示出确实的路径,而非使用链接 (link) 路径。
#范例:单纯显示出目前的工作目录:
[root@study ~]# pwd
/root <== 显示出目录啦~

#范例:显示出实际的工作目录,而非链接文件本身的目录名而已
[root@study ~]# cd /var/mail <==注意,/var/mail 是一个连结档
[root@study mail]# pwd
/var/mail <==列出目前的工作目录
[root@study mail]# pwd -P
/var/spool/mail <==怎么回事?有没有加 -P 差很多~
[root@study mail]# ls -ld /var/mail
lrwxrwxrwx. 1 root root 10 May 4 17:51 /var/mail -> spool/mail
# 看到这里应该知道为啥了吧?因为 /var/mail 是连结档,连结到 /var/spool/mail
# 所以,加上 pwd -P 的选项后,会不以连结文件的数据显示,而是显示正确的完整路径啊!
mkdir (make directory, 建立新目录)
[root@study ~]# mkdir [-mp] 目录名称
选项与参数:
-m :配置文件案的权限喔!直接设定,不需要看预设权限 (umask) 的脸色~
-p :帮助你直接将所需要的目录(包含上层目录)递归建立起来!

#范例:请到/tmp 底下尝试建立数个新目录看看:
[root@study ~]# cd /tmp
[root@study tmp]# mkdir test <==建立一名为 test 的新目录
[root@study tmp]# mkdir test1/test2/test3/test4
mkdir: cannot create directory ‘test1/test2/test3/test4’: No such file or directory
# 话说,系统告诉我们,没可能建立这个目录啊!就是没有目录才要建立的!见鬼嘛?
[root@study tmp]# mkdir -p test1/test2/test3/test4
# 原来是要建 test4 上层没先建 test3 之故!加了这个 -p 的选项,可以自行帮你建立多层目录!

#范例:建立权限为 rwx--x--x 的目录
[root@study tmp]# mkdir -m 711 test2
[root@study tmp]# ls -ld test*
drwxr-xr-x. 2 root root 6 Jun 4 19:03 test
drwxr-xr-x. 3 root root 18 Jun 4 19:04 test1
drwx--x--x. 2 root root 6 Jun 4 19:05 test2
# 仔细看上面的权限部分,如果没有加上 -m 来强制设定属性,系统会使用默认属性。
# 那么你的默认属性为何?777 & 022 = 755 这要透过底下介绍的 umask 才能了解喔! ^_^

我们可以利用 -m 来强制给予一个新的目录相关的权限, 例如上表当中,我们给予 -m 711 来给予新的目录 drwx–x–x 的权限。不过,如果没有给予 -m 选项时, 那么默认的新建目录权限又是什么呢?这个跟 umask 有关,我们在本章后头会加以介绍的。

rmdir (remove directory, 删除『空』的目录)
[root@study ~]# rmdir [-p] 目录名称
选项与参数:
-p :连同『上层』『空的』目录也一起删除

#范例:将于 mkdir 范例中建立的目录(/tmp 底下)删除掉!
[root@study tmp]# ls -ld test* <==看看有多少目录存在?
drwxr-xr-x. 2 root root 6 Jun 4 19:03 test
drwxr-xr-x. 3 root root 18 Jun 4 19:04 test1
drwx--x--x. 2 root root 6 Jun 4 19:05 test2
[root@study tmp]# rmdir test <==可直接删除掉,没问题
[root@study tmp]# rmdir test1 <==因为尚有内容,所以无法删除!
rmdir: failed to remove ‘test1’: Directory not empty
[root@study tmp]# rmdir -p test1/test2/test3/test4
[root@study tmp]# ls -ld test* <==您看看,底下的输出中 test 与 test1 不见了!
drwx--x--x. 2 root root 6 Jun 4 19:05 test2
# 瞧!利用 -p 这个选项,立刻就可以将 test1/test2/test3/test4 一次删除~
# 不过要注意的是,这个 rmdir 仅能『删除空的目录』喔!

12.3 关于执行文件路径的变量: $PATH

我们知道查阅文件属性的指令 ls 完整文件名为:/bin/ls(这是绝对路径),那你会不会觉得很奇怪:『为什么我可以在任何地方执行/bin/ls 这个指令呢? 』 为什么我在任何目录下输入 ls 就一定可以显示出一些讯息而不会说找不到该 /bin/ls 指令呢? 这是因为环境变量PATH 的帮助所致呀

当我们在执行一个指令的时候,举例来说『ls』好了,系统会依照 PATH 的设定去每个 PATH 定义的目录下搜寻文件名为 ls 的可执行文件,如果在 PATH 定义的目录中含有多个文件名为 ls 的可执行文件,那么先搜寻到的同名指令先被执行!

# 范例:先用 root 的身份列出搜寻的路径为何?
[root@study ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

# 范例:用 dmtsai 的身份列出搜寻的路径为何?
[root@study ~]# exit # 由之前的 su - 离开,变回原本的账号!或再取得一个终端机皆可!
[dmtsai@study ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
# 记不记得我们前一章说过,目前 /bin 是连结到 /usr/bin 当中的喔!
[root@node-135 test2]# ll /bin
lrwxrwxrwx. 1 root root 7 Jul 14 17:27 /bin -> usr/bin

PATH(一定是大写)这个变量的内容是由一堆目录所组成的,每个目录中间用冒号(:)来隔开, 每个目录是有『顺序』之分的。

我们用几个范例来让你了解一下,为什么 PATH 是那么重要的项目!

  1. 例题
    假设你是 root,如果你将 ls 由/bin/ls 移动成为/root/ls(可用『mv /bin/ls /root』指令达成),然后你自己本身也在/root目录下, 请问:
  • (1)你能不能直接输入 ls 来执行?

  • (2)若不能,你该如何执行 ls 这个指令?

  • (3)若要直接输入 ls 即可执行,又该如何进行?

    答:
    由于这个例题的重点是将某个执行文件移动到非正规目录去,所以我们先要进行底下的动作才行:(务必先使用 su - 切换成为 root 的身份)

    [root@study ~]# mv /bin/ls /root
    # mv 为移动,可将文件在不同的目录间进行移动作业
    
    • (1)接下来不论你在那个目录底下输入任何与 ls 相关的指令,都没有办法顺利的执行 ls 了! 也就是说,你不能直接输入 ls 来执行,因为/root 这个目录并不在 PATH 指定的目录中, 所以,即使你在/root 目录下,也不能够搜寻到 ls这个指令!
    • (2)因为这个 ls 确实存在于/root 底下,并不是被删除了!所以我们可以透过使用绝对路径或者是相对路径直接指定这个执行档档名, 底下的两个方法都能够执行 ls 这个指令:
    [root@study ~]# /root/ls <==直接用绝对路径指定该文件名
    [root@study ~]# ./ls <==因为在 /root 目录下,就用./ls 来指定
    
    • (3)如果想要让 root 在任何目录均可执行/root 底下的 ls,那么就将/root 加入 PATH 当中即可。 加入的方法很简单,就像底下这样:
    [root@study ~]# PATH="${PATH}:/root"
    

    某些情况下,即使你已经将 ls 搬回 /bin 了,不过系统还是会告知你无法处理 /root/ls 喔!很可能是因为指令参数被快取的关系。 不要紧张,只要注销 (exit) 再登入 (su -) 就可以继续快乐的使用 ls 了!

  1. 例题
    如果我有两个 ls 指令在不同的目录中,例如/usr/local/bin/ls 与/bin/ls 那么当我下达 ls 的时候,哪个 ls 会被执行?
    答:
    那还用说,就找出 ${PATH} 里面哪个目录先被查询,则那个目录下的指令就会被先执行了!所以用 dmtsai 账号为例,他最先搜寻的是 /usr/local/bin, 所以 /usr/local/bin/ls 会先被执行喔!

  2. 例题
    为什么 ${PATH} 搜寻的目录不加入本目录(.)? 加入本目录的搜寻不是也不错?
    答:
    如果在 PATH 中加入本目录(.)后,确实我们就能够在指令所在目录进行指令的执行了。 但是由于你的工作目录并非固定(常常会使用 cd 来切换到不同的目录),因此能够执行的指令会有变动(因为每个目录底下的可执行文件都不相同嘛!),这对使用者来说并非好事。

    另外,如果有个坏心使用者在/tmp 底下做了一个指令,因为/tmp 是大家都能够写入的环境,所以他当然可以这样做。 假设该指令可能会窃取用户的一些数据,如果你使用 root 的身份来执行这个指令,那不是很糟糕? 如果这个指令的名称又是经常会被用到的 ls 时,那『中标』的机率就更高了!

    所以,为了安全起见,不建议将『.』加入 PATH 的搜寻目录中。

而由上面的几个例题我们也可以知道几件事情:

  • 不同身份使用者预设的 PATH 不同,默认能够随意执行的指令也不同(如 root 与 dmtsai);
  • PATH 是可以修改的;
  • 使用绝对路径或相对路径直接指定某个指令的文件名来执行,会比搜寻 PATH 来的正确;
  • 指令应该要放置到正确的目录下,执行才会比较方便;
  • 本目录(.)最好不要放到 PATH 当中。

12.4 文件与目录的检视: ls

[root@study ~]# ls [-aAdfFhilnrRSt] 文件名或目录名称..
[root@study ~]# ls [--color={never,auto,always}] 文件名或目录名称..
[root@study ~]# ls [--full-time] 文件名或目录名称..
选项与参数:
-a :全部的文件,连同隐藏档( 开头为 . 的文件) 一起列出来(常用)
-A :全部的文件,连同隐藏档,但不包括 ... 这两个目录
-d :仅列出目录本身,而不是列出目录内的文件数据(常用)
-f :直接列出结果,而不进行排序 (ls 预设会以档名排序!)
-F :根据文件、目录等信息,给予附加数据结构,例如:*:代表可执行文件; /:代表目录; =:代表 socket 文件; |:代表 FIFO 文件;
-h :将文件容量以人类较易读的方式(例如 GB, KB 等等)列出来;
-i :列出 inode 号码,inode 的意义下一章将会介绍;
-l :长数据串行出,包含文件的属性与权限等等数据;(常用)
-n :列出 UID 与 GID 而非使用者与群组的名称 (UID 与 GID 会在账号管理提到!)
-r :将排序结果反向输出,例如:原本档名由小到大,反向则为由大到小;
-R :连同子目录内容一起列出来,等于该目录下的所有文件都会显示出来;
-S :以文件容量大小排序,而不是用档名排序;
-t :依时间排序,而不是用档名。
--color=never :不要依据文件特性给予颜色显示;
--color=always :显示颜色
--color=auto :让系统自行依据设定来判断是否给予颜色
--full-time :以完整时间模式 (包含年、月、日、时、分) 输出
--time={atime,ctime} :输出 access 时间或改变权限属性时间 (ctime) 而非内容变更时间 (modification time)

当你只有下达 ls 时,默认显示的只有:非隐藏档的档名、 以档名进行排序及文件名代表的颜色显示如此而已。

# 范例一 ls /home/yurq 和ls /home/yurq/* 不同
[root@node-138 tmp]# ls /home/yurq
0logwatch  123  70001  70002  addaccount.sh  helloworld  learn-terraform-docker-container  test1
[root@node-138 tmp]# ls /home/yurq/*
/home/yurq/0logwatch  /home/yurq/123  /home/yurq/70001  /home/yurq/70002  /home/yurq/addaccount.sh

/home/yurq/helloworld:
a.out  hello  hello.c  hello.o  sin.c  thanks  thanks_2.c  thanks_2.o  thanks.c  thanks.o

/home/yurq/learn-terraform-docker-container:
main.tf  terraform.tfstate

/home/yurq/test1:
123  321

RHCSA考试:ls /home/yurq/*会列出目录及其子目录内所有文件及目录,ls /home/yurq仅列出目录内文件及目录

12.5 复制、删除与移动: cp, rm, mv, rename

要复制文件,请使用 cp (copy) 这个指令即可~不过, cp 这个指令的用途可多了~ 除了单纯的复制之外,还可以建立连结档 (就是快捷方式啰),比对两文件的新旧而予以更新, 以及复制整个目录等等的功能呢!至于移动目录与文件,则使用 mv (move), 这个指令也可以直接拿来作更名 (rename) 的动作喔!至于移除吗?那就是 rm (remove) 这个指令啰~底下我们就来瞧一瞧先~

cp (复制文件或目录)
[root@study ~]# cp [-adfilprsu] 来源文件(source) 目标文件(destination)
[root@study ~]# cp [options] source1 source2 source3 .... directory
选项与参数:
-a :相当于 -dr --preserve=all 的意思,至于 dr 请参考下列说明;(常用)
-d :若来源文件为链接文件的属性(link file),则复制链接文件属性而非文件本身;
-f :为强制(force)的意思,若目标文件已经存在且无法开启,则移除后再尝试一次;
-i :若目标文件(destination)已经存在时,在覆盖时会先询问动作的进行(常用)
-l :进行硬式连结(hard link)的连结档建立,而非复制文件本身;
-p :连同文件的属性(权限、用户、时间)一起复制过去,而非使用默认属性(备份常用)-r :递归持续复制,用于目录的复制行为;(常用)
-s :复制成为符号链接文件 (symbolic link),亦即『快捷方式』文件;
-u :destination 比 source 旧才更新 destination,或 destination 不存在的情况下才复制。
--preserve=all :除了 -p 的权限相关参数外,还加入 SELinux 的属性, links, xattr 等也复制了。

最后需要注意的,如果来源档有两个以上,则最后一个目的文件一定要是『目录』才行!

复制(cp)这个指令是非常重要的,不同身份者执行这个指令会有不同的结果产生,尤其是那个-a, -p 的选项, 对于不同身份来说,差异则非常的大!底下的练习中,有的身份为 root 有的身份为一般账号(在我这里用 dmtsai 这个账号),练习时请特别注意身份的差别喔!好!开始来做复制的练习与观察:

# 范例一:用 root 身份,将家目录下的 .bashrc 复制到 /tmp 下,并更名为 bashrc
[root@study ~]# cp ~/.bashrc /tmp/bashrc
[root@study ~]# cp -i ~/.bashrc /tmp/bashrc
cp: overwrite `/tmp/bashrc'? n <==n 不覆盖,y 为覆盖
# 重复作两次动作,由于 /tmp 底下已经存在 bashrc 了,加上 -i 选项后,
# 则在覆盖前会询问使用者是否确定!可以按下 n 或者 y 来二次确认呢!

# 范例二:变换目录到/tmp,并将/var/log/wtmp 复制到/tmp 且观察属性:
[root@study ~]# cd /tmp
[root@study tmp]# cp /var/log/wtmp . <==想要复制到当前目录,最后的 . 不要忘
[root@study tmp]# ls -l /var/log/wtmp wtmp
-rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 /var/log/wtmp
-rw-r--r--. 1 root root 28416 Jun 11 19:01 wtmp
# 注意上面的特殊字体,在不加任何选项的情况下,文件的某些属性/权限会改变;
# 这是个很重要的特性!要注意喔!还有,连文件建立的时间也不一样了!
# 那如果你想要将文件的所有特性都一起复制过来该怎办?可以加上 -a 喔!如下所示:
[root@study tmp]# cp -a /var/log/wtmp wtmp_2
[root@study tmp]# ls -l /var/log/wtmp wtmp_2
-rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 /var/log/wtmp
-rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 wtmp_2
# 瞭了吧!整个资料特性完全一模一样ㄟ!真是不赖~这就是 -a 的特性!

这个 cp 的功能很多,由于我们常常会进行一些数据的复制,所以也会常常用到这个指令的。 一般来说,我们如果去复制别人的数据 (当然,该文件你必须要有 read 的权限才行啊!) 时, 总是希望复制到的数据最后是我们自己的,所以,在预设的条件中, cp 的来源档与目的档的权限是不同的,目的档的拥有者通常会是指令操作者本身。举例来说, 上面的范例二中,由于我是 root 的身份,因此复制过来的文件拥有者与群组就改变成为 root 所有了! 这样说,可以明白吗?

由于具有这个特性**,因此当我们在进行备份的时候,某些需要特别注意的特殊权限文件**, 例如密码文件 (/etc/shadow) 以及一些配置文件,就不能直接以 cp 来复制,而必须要加上-a或者是-p等等可以完整复制文件权限的选项才行!另外,如果你想要复制文件给其他的使用者, 也必须要注意到文件的权限(包含读、写、执行以及文件拥有者等等), 否则,其他人还是无法针对你给予的文件进行修订的动作喔!注意注意!

#范例三:复制 /etc/ 这个目录下的所有内容到 /tmp 底下
[root@study tmp]# cp /etc/ /tmp
cp: omitting directory `/etc' <== 如果是目录则不能直接复制,要加上 -r 的选项
[root@study tmp]# cp -r /etc/ /tmp
# 还是要再次的强调喔! -r 是可以复制目录,但是,文件与目录的权限可能会被改变
# 所以,也可以利用『 cp -a /etc /tmp 』来下达指令喔!尤其是在备份的情况下!

#范例四:将范例一复制的 bashrc 建立一个连结档 (symbolic link)
[root@study tmp]# ls -l bashrc
-rw-r--r--. 1 root root 176 Jun 11 19:01 bashrc <==先观察一下文件情况
[root@study tmp]# cp -s bashrc bashrc_slink
[root@study tmp]# cp -l bashrc bashrc_hlink
[root@study tmp]# ls -l bashrc*
-rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc <==与源文件不太一样了!
-rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc_hlink
lrwxrwxrwx. 1 root root 6 Jun 11 19:06 bashrc_slink -> bashrc

范例四可有趣了!使用 -l 及 -s 都会建立所谓的连结档(link file),但是这两种连结档却有不一样的情况。这是怎么一回事啊? 那个 -l 就是所谓的实体链接(hard link),至于 -s 则是符号链接(symbolic link), 简单来说,bashrc_slink 是一个『快捷方式』,这个快捷方式会连结到bashrc 去!所以你会看到档名右侧会有个指向(->)的符号!至于 bashrc_hlink 文件与 bashrc 的属性与权限完全一模一样,与尚未进行连结前的差异则是第二栏的link 数由 1 变成 2 了!

# 范例五:若 ~/.bashrc 比 /tmp/bashrc 新才复制过来
[root@study tmp]# cp -u ~/.bashrc /tmp/bashrc
# 这个 -u 的特性,是在目标文件与来源文件有差异时,才会复制的。
# 所以,比较常被用于『备份』的工作当中喔! ^_^

# 范例六:将范例四造成的 bashrc_slink 复制成为 bashrc_slink_1 与 bashrc_slink_2
[root@study tmp]# cp bashrc_slink bashrc_slink_1
[root@study tmp]# cp -d bashrc_slink bashrc_slink_2
[root@study tmp]# ls -l bashrc bashrc_slink*
-rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc
lrwxrwxrwx. 1 root root 6 Jun 11 19:06 bashrc_slink -> bashrc
-rw-r--r--. 1 root root 176 Jun 11 19:09 bashrc_slink_1 <==与源文件相同
lrwxrwxrwx. 1 root root 6 Jun 11 19:10 bashrc_slink_2 -> bashrc <==是连结档!
# 这个例子也是很有趣喔!原本复制的是连结档,但是却将连结档的实际文件复制过来了
# 也就是说,如果没有加上任何选项时,cp 复制的是源文件,而非链接文件的属性!
# 若要复制链接文件的属性,就得要使用 -d 的选项了!如 bashrc_slink_2 所示。

# 范例七:将家目录的 .bashrc 及 .bash_history 复制到 /tmp 底下
[root@study tmp]# cp ~/.bashrc ~/.bash_history /tmp
# 可以将多个数据一次复制到同一个目录去!最后面一定是目录!

# 范例八:你能否使用 dmtsai 的身份,完整的复制/var/log/wtmp 文件到/tmp 底下,并更名为 dmtsai_wtmp 呢?
[dmtsai@study ~]$ cp -a /var/log/wtmp /tmp/dmtsai_wtmp
[dmtsai@study ~]$ ls -l /var/log/wtmp /tmp/dmtsai_wtmp
-rw-rw-r--. 1 dmtsai dmtsai 28416 611 18:56 /tmp/dmtsai_wtmp
-rw-rw-r--. 1 root utmp 28416 611 18:56 /var/log/wtmp
# 由于 dmtsai 的身份并不能随意修改文件的拥有者与群组,因此虽然能够复制 wtmp 的相关权限与时间等属性
# 但是是与拥有者、群组相关的,原本 dmtsai 身份无法进行的动作,即使加上 -a 选项,也是无法达成完整复制权限的!

总之,由于 cp 有种种的文件属性与权限的特性,所以,在复制时,你必须要清楚的了解到:

  • 是否需要完整的保留来源文件的信息? ==> -a?
  • 来源文件是否为连结档 (symbolic link file)? ==> -d?复制链接本身 -s?创建符号连接 -l?硬链接
  • 来源档是否为特殊的文件,例如 FIFO, socket 等? ==> -a
  • 来源文件是否为目录?==> -r

注意:关于cp后权限问题
root用户:

  • cp uid:gid都为root;
  • cp -p uid:gid保持原始不变;
    普通用户:
  • cp uid:gid对应当前普通用户uid:gid,权限为原始权限和当前用户umask相与;
  • cp -p uid:gid对应当前普通用户uid:gid;
rm (移除文件或目录)
[root@study ~]# rm [-fir] 文件或目录
选项与参数:
-f :就是 force 的意思,忽略不存在的文件,不会出现警告讯息;
-i :互动模式,在删除前会询问使用者是否动作
-r :递归删除啊!最常用在目录的删除了!这是非常危险的选项!!!
# 范例一:将刚刚在 cp 的范例中建立的 bashrc 删除掉!
[root@study ~]# cd /tmp
[root@study tmp]# rm -i bashrc
#rm: remove regular file `bashrc'? y
# 如果加上 -i 的选项就会主动询问喔,避免你删除到错误的档名!

# 范例二:透过通配符*的帮忙,将/tmp 底下开头为 bashrc 的档名通通删除:
[root@study tmp]# rm -i bashrc*
# 注意那个星号,代表的是 0 到无穷多个任意字符喔!很好用的东西!

# 范例三:将 cp 范例中所建立的 /tmp/etc/ 这个目录删除掉!
[root@study tmp]# rmdir /tmp/etc
rmdir: failed to remove '/tmp/etc': Directory not empty <== 删不掉啊!因为这不是空的目录!
[root@study tmp]# rm -r /tmp/etc
rm: descend into directory `/tmp/etc'? y
rm: remove regular file `/tmp/etc/fstab'? y
rm: remove regular empty file `/tmp/etc/crypttab'? ^C <== 按下 [crtl]+c 中断
.....(中间省略).....
# 因为身份是 root ,预设已经加入了 -i 的选项,所以你要一直按 y 才会删除!
# 如果不想要继续按 y ,可以按下『 [ctrl]-c 』来结束 rm 的工作。
# 这是一种保护的动作,如果确定要删除掉此目录而不要询问,可以这样做:
[root@study tmp]# \rm -r /tmp/etc
# 在指令前加上反斜杠,可以忽略掉 alias 的指定选项喔!
# 拜托!这个范例很可怕!你不要删错了!删除 /etc 系统是会挂掉的!

# 范例四:删除一个带有 - 开头的文件
[root@study tmp]# touch ./-aaa- <==touch 这个指令可以建立空文件!
[root@study tmp]# ls -l 
-rw-r--r--. 1 root root 0 Jun 11 19:22 -aaa- <==文件大小为 0,所以是空文件
[root@study tmp]# rm -aaa-
rm: invalid option -- 'a' <== 因为 "-" 是选项嘛!所以系统误判了!
Try 'rm ./-aaa-' to remove the file `-aaa-'. <== 新的 bash 有给建议的
Try 'rm --help' for more information.
[root@study tmp]# rm ./-aaa

在指令前加上反斜杠,可以忽略掉 alias 的指定选项喔!\rm -r /tmp/etc
删除一个带有 - 开头的文件 rm ./-aaa

这是移除的指令(remove),要注意的是,通常在 Linux 系统下,为了怕文件被 root 误杀,所以很多distributions 都已经默认加入 -i 这个选项了!而如果要连目录下的东西都一起杀掉的话, 例如子目录里面还有子目录时,那就要使用 -r 这个选项了!不过,使用『 rm -r 』这个指令之前,请千万注意了,因为该目录或文件『肯定』会被 root 杀掉!因为系统不会再次询问你是否要砍掉呦!所以那是个超级严重的指令下达呦! 得特别注意!不过,如果你确定该目录不要了,那么使用 rm -r 来循环杀掉是不错的方式!

另外,范例四也是很有趣的例子,我们在之前就谈过,档名最好不要使用 “-” 号开头, 因为 “-” 后面接的是选项,因此,单纯的使用『 rm -aaa- 』系统的指令就会误判啦! 那如果使用后面会谈到的正规表示法时,还是会出问题的!所以,只能用避过首位字符是 “-” 的方法啦!就是加上本目录『./』即可!如果 man rm 的话,其实还有一种方法,那就是『 rm -- -aaa- 』也可以啊!

mv (移动文件与目录,或更名)
[root@study ~]# mv [-fiu] source destination
[root@study ~]# mv [options] source1 source2 source3 .... directory
选项与参数:
-f :force 强制的意思,如果目标文件已经存在,不会询问而直接覆盖;
-i :若目标文件 (destination) 已经存在时,就会询问是否覆盖!
-u :若目标文件已经存在,且 source 比较新,才会更新 (update)
# 范例一:复制一文件,建立一目录,将文件移动到目录中
[root@study ~]# cd /tmp
[root@study tmp]# cp ~/.bashrc bashrc
[root@study tmp]# mkdir mvtest
[root@study tmp]# mv bashrc mvtest
# 将某个文件移动到某个目录去,就是这样做!

# 范例二:将刚刚的目录名称更名为 mvtest2
[root@study tmp]# mv mvtest mvtest2 <== 这样就更名了!简单~
# 其实在 Linux 底下还有个有趣的指令,名称为 rename ,
# 该指令专职进行多个档名的同时更名,并非针对单一档名变更,与 mv 不同。请 man rename。

# 范例三:再建立两个文件,再全部移动到 /tmp/mvtest2 当中
[root@study tmp]# cp ~/.bashrc bashrc1
[root@study tmp]# cp ~/.bashrc bashrc2
[root@study tmp]# mv bashrc1 bashrc2 mvtest2
# 注意到这边,如果有多个来源文件或目录,则最后一个目标文件一定是『目录!』
# 意思是说,将所有的数据移动到该目录的意思!

这是搬移 (move) 的意思!当你要移动文件或目录的时后,呵呵!这个指令就很重要啦! 同样的,你也可以使用 -u ( update )来测试新旧文件,看看是否需要搬移啰!另外一个用途就是『变更档名!』,我们可以很轻易的使用 mv 来变更一个文件的档名呢!不过,在 Linux 才有的指令当中,有个rename , 可以用来更改大量文件的档名,你可以利用 man rename 来查阅一下,也是挺有趣的指令喔!

rename(用字符串替换的方式批量改变文件名)
rename [options] expression replacement file...
# 原字符串:将文件名需要替换的字符串;
# 目标字符串:将文件名中含有的原字符替换成目标字符串;
# 文件:指定要改变文件名的文件列表。
OPTIONS
       -v, --verbose
              Give visual feedback which files where renamed, if any.
       -V, --version
              Display version information and exit.
       -s, --symlink
              Peform rename on symlink target

rename支持通配符,基本的通配符有以下几个:

  • ? 可替代单个字符
  • * 可替代多个字符
  • [charset] 可替代charset集中的任意单个字符

文件夹中有这些文件foo1, …, foo9, foo10, …, foo278

  • 如果使用rename foo foo0 foo?仅会把foo1到foo9的文件重命名为foo01到foo09,重命名的文件只是有4个字符长度名称的文件,文件名中的foo被替换为foo0。
  • 如果使用rename foo foo0 foo??foo01到foo99的所有文件都被重命名为foo001到foo099,只重命名5个字符长度名称的文件,文件名中的foo被替换为foo0。
  • 如果使用rename foo foo0 foo*,foo001到foo278的所有文件都被重命名为foo0001到foo0278,所有以foo开头的文件都被重命名
  • 如果使用rename foo0 foo foo0[2]*,从foo0200到foo0278的所有文件都被重命名为foo200到foo278,文件名中的foo0被替换为foo。
[root@node-135 yurq]# touch foo{1..5}
[root@node-135 yurq]# ll
total 40
-rw-r--r-- 1 root root   40 Aug  3 17:28 file.sed
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo1
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo2
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo3
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo4
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo5
[root@node-135 yurq]# rename foo foo0 foo?
[root@node-135 yurq]# ll
total 40
-rw-r--r-- 1 root root   40 Aug  3 17:28 file.sed
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo01
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo02
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo03
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo04
-rw-r--r-- 1 root root    0 Aug  8 11:10 foo05

12.6 取得路径的文件名与目录名称:dirname, basename

每个文件的完整档名包含了前面的目录与最终的文件名,而每个档名的长度都可以到达 255 个字符耶! 那么你怎么知道那个是档名?那个是目录名?嘿嘿!就是利用斜线 (/) 来分辨啊! 其实,取得文件名或者是目录名称,一般的用途应该是在写程序的时候用来判断之用的啦~ 底下我们简单的以几个范例来谈一谈 basename 与dirname 的用途!

[root@study ~]# basename /etc/sysconfig/network
network <== 很简单!就取得最后的档名~
[root@study ~]# dirname /etc/sysconfig/network
/etc/sysconfig <== 取得的变成目录名了!

该系列目录 --> 【BASH】回顾与知识点梳理(目录)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值