高级Bash脚本编程指南(28):文件与归档命令(一)

高级Bash脚本编程指南(28):文件与归档命令(一)

成于坚持,败于止步

归档命令

tar

标准的UNIX归档工具. 起初这只是一个磁带归档程序, 而现在这个工具已经被开发为通用打包程序, 它能够处理所有设备的所有类型的归档文件, 包括磁带设备, 正常文件, 甚至是stdout. GNU的tar工具现在可以接受不同种类的压缩过滤器

比如tar czvf archive_name.tar.gz *, 并且可以递归的处理归档文件, 还可以用gzips压缩目录下的所有文件, 除了当前目录下($PWD)的点文件. 

一些有用的tar命令选项:
-c 创建(一个新的归档文件)
-x 解压文件(从存在的归档文件中)
--delete 删除文件(从存在的归档文件中)

这个选项不能用于磁带类型设备.
-r 将文件添加到现存的归档文件的尾部
-A 将tar文件添加到现存的归档文件的尾部
-t 列出现存的归档文件中包含的内容
-u 更新归档文件
-d 使用指定的文件系统, 比较归档文件
-z 用gzip压缩归档文件(压缩还是解压, 依赖于是否组合了-c或-x)选项
-j 用bzip2压缩归档文件

如果想从损坏的用gzipped压缩过的tar文件中取得数据, 那将是非常困难的. 所以当我们归档重要的文件的时候, 一定要保留多个备份.

分享个我一直使用的解压,压缩命令集:http://blog.csdn.net/xinyuwuxian/article/details/8872730 O(∩_∩)O~

shar

Shell归档工具. 存在于shell归档文件中的所有文件都是未经压缩的, 并且本质上是一个shell脚本, 以#!/bin/sh开头, 并且包含所有必要的解档命令. Shar 归档文件至今还在Internet新闻组中使用, 否则的话, shar早就被tar/gzip所取代了. unshar命令用来解档shar归档文件.

ar

创建和操作归档文件的工具, 主要在对二进制目标文件打包成库时才会用到.

rpm

Red Hat包管理器, 或者说rpm工具提供了一种对源文件或二进制文件进行打包的方法. 除此之外, 它还包括安装命令, 并且还检查包的完整性.

一个简单的rpm -i package_name.rpm命令对于安装一个包来说就足够了, 虽然这个命令还有好多其它的选项.

rpm -qf 列出一个文件属于那个包

bash$ rpm -qf /bin/ls
coreutils-5.2.1-31
rpm -qa将会列出给定系统上所有安装了的 rpm包. rpm -qa package_name命令将会列出与给定名字package_name相匹配的包
bash$ rpm -qa
redhat-logos-1.1.3-1
 glibc-2.2.4-13
 cracklib-2.7-12
 dosfstools-2.7-1
 gdbm-1.8.0-10
 ksymoops-2.4.1-1
 mktemp-1.5-11
 perl-5.6.0-17
 reiserfs-utils-3.x.0j-2
 ...


bash$ rpm -qa docbook-utils
docbook-utils-0.6.9-2


bash$ rpm -qa docbook | grep docbook
docbook-dtd31-sgml-1.0-10
 docbook-style-dsssl-1.64-3
 docbook-dtd30-sgml-1.0-10
 docbook-dtd40-sgml-1.0-11
 docbook-utils-pdf-0.6.9-2
 docbook-dtd41-sgml-1.0-10
 docbook-utils-0.6.9-2

一直在用ubuntu,red hat几乎不在考虑范围之内,O(∩_∩)O~,这里知道就好

cpio

这个特殊的归档拷贝命令(拷贝输入和输出, copy input and output)现在已经很少能见到了, 因为它已经被tar/gzip所替代了. 现在这个命令只在一些比较特殊的地方还在使用, 比如拷贝一个目录树. 如果指定一个合适尺寸的块(用于拷贝), 那么这个命令会比tar命令快一些.

#!/bin/bash

# 使用cpio来拷贝目录树.

# 使用'cpio'的优点:
#   加速拷贝. 比通过管道使用'tar'命令快一些.
#   很适合拷贝一些'cp'命令
#+  搞不定的的特殊文件(比如名字叫pipes的文件, 等等)

ARGS=2
E_BADARGS=65

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` source destination"
  exit $E_BADARGS
fi

source=$1
destination=$2


find "$source" -depth | cpio -admvp "$destination"
#               ^^^^^         ^^^^^
# 阅读'find'和'cpio'的man页来了解这些选项的意义.


# 练习:
# -----

#  添加一些代码来检查'find | cpio'管道命令的退出码($?)
#+ 并且如果出现错误的时候输出合适的错误码.

exit 0
结果:
root@ubuntu:~/resource/shell-study/0622-2013# ./test1.sh /root/resource/shell-study/0621-2013/ /root/resource/shell-study/
/root/resource/shell-study//root/resource/shell-study/0621-2013/test1.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/test10.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/file.unx
/root/resource/shell-study//root/resource/shell-study/0621-2013/file-d
/root/resource/shell-study//root/resource/shell-study/0621-2013/test7.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/test6.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/test8.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/test2.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/file-u
/root/resource/shell-study//root/resource/shell-study/0621-2013/test4.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/test9.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/test3.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/file
/root/resource/shell-study//root/resource/shell-study/0621-2013/test5.sh
/root/resource/shell-study//root/resource/shell-study/0621-2013/
14 blocks
root@ubuntu:~/resource/shell-study/0622-2013# ls
test1.sh
root@ubuntu:~/resource/shell-study/0622-2013# cd ..
root@ubuntu:~/resource/shell-study# ls
0426-2013  0504-2013  0507-2013  0509-2013  0613-2013  0615-2013  0619-2013  0621-2013  root
0427-2013  0506-2013  0508-2013  0609-2013  0614-2013  0618-2013  0620-2013  0622-2013
root@ubuntu:~/resource/shell-study# cd root/resource/shell-study/0621-2013/
file       file-d     file-u     file.unx   test10.sh  test1.sh   test2.sh   test3.sh   test4.sh   test5.sh   test6.sh   test7.sh   test8.sh   test9.sh   
root@ubuntu:~/resource/shell-study# cd root/resource/shell-study/0621-2013/

rpm2cpio

这个命令可以从rpm归档文件中解出一个cpio归档文件.

一个实例:解包一个rpm归档文件

#!/bin/bash
# de-rpm.sh: 解包一个'rpm'归档文件

: ${1?"Usage: `basename $0` target-file"}
# 必须指定'rpm'归档文件名作为参数.


TEMPFILE=$$.cpio # Tempfile必须是一个"唯一"的名字.
# $$是这个脚本的进程ID.

rpm2cpio < $1 > $TEMPFILE # 将rpm归档文件转换为cpio归档文件.
cpio --make-directories -F $TEMPFILE -i # 解包cpio归档文件.
rm -f $TEMPFILE # 删除cpio归档文件.

exit 0

压缩命令

gzip

标准的GNU/UNIX压缩工具, 取代了比较差的compress命令. 相应的解压命令是gunzip, 与gzip -d是等价的.

-c选项将会把gzip的输出打印到stdout上. 当你想通过管道传递到其他命令的时候, 这就非常有用了.

zcat过滤器可以将一个gzip文件解压到stdout, 所以尽可能的使用管道和重定向. 这个命令事实上就是一个可以工作于压缩文件(包括一些的使用老的compress工具压缩的文件)的cat命令. zcat命令等价于gzip -dc.

在某些商业的UNIX系统上, zcat与uncompress -c等价, 并且不能工作于gzip文件.

bzip2

用来压缩的一个可选的工具, 通常比gzip命令压缩率更高(所以更慢), 适用于比较大的文件. 相应的解压命令是bunzip2.

compress, uncompress

这是一个老的, 私有的压缩工具, 一般的商业UNIX发行版都会有这个工具. 更有效率的gzip工具早就把这个工具替换掉了. Linux发行版一般也会包含一个兼容的compress命令, 虽然gunzip也可以解压用compress工具压缩的文件.

znew命令可以将compress压缩的文件转换为gzip压缩的文件.

sq

另一种压缩工具, 一个只能工作于排过序的ASCII单词列表的过滤器. 这个命令使用过滤器标准的调用语法, sq < input-file > output-file. 速度很快, 但是效率远不及gzip. 相应的解压命令为unsq, 调用方法与sq相同.

sq的输出可以通过管道传递给gzip, 以便于进一步的压缩.

zip, unzip

跨平台的文件归档和压缩工具, 与DOS下的pkzip.exe兼容. "Zip"归档文件看起来在互联网上比"tar包"更流行.

unarc, unarj, unrar

这些Linux工具可以用来解档那些用DOS下的arc.exe, arj.exe, 和rar.exe 程序进行归档的文件.

文件信息

file

确定文件类型的工具. 命令file file-name将会用ascii文本或数据的形式返回file-name文件的详细描述. 这个命令会使用/usr/share/magic, /etc/magic, 或/usr/lib/magic中定义的魔法数字来标识包含某种魔法数字的文件, 上边所举出的这3个文件需要依赖于具体的 Linux/UNIX 发行版.

-f选项将会让file命令运行于批处理模式, 也就是说它会分析-f后边所指定的文件, 从中读取需要处理的文件列表, 然后依次执行file命令. 

-z选项, 当对压缩过的目标文件使用时, 将会强制分析压缩的文件类型

bash$ file test.tar.gz
test.tar.gz: gzip compressed data, deflated, last modified: Sun Sep 16 13:34:51 2001, os: Unix

bash file -z test.tar.gz
test.tar.gz: GNU tar archive (gzip compressed data, deflated, last modified: Sun Sep 16 13:34:51 2001, os: Unix)
#!/bin/bash
# 在给定的目录中找出sh和Bash脚本文件:

DIRECTORY=/usr/bin
KEYWORD=Bourne
# Bourne和Bourne-Again shell脚本

file $DIRECTORY/* | fgrep $KEYWORD

exit 0
结果:
root@ubuntu:~/resource/shell-study/0622-2013# ./test2.sh 
/usr/bin/aptitude-create-state-bundle:            Bourne-Again shell script text executable
/usr/bin/aptitude-run-state-bundle:               Bourne-Again shell script text executable
/usr/bin/cautious-launcher:                       Bourne-Again shell script text executable
/usr/bin/checkbox-gtk:                            Bourne-Again shell script text executable
/usr/bin/f-spot:                                  Bourne-Again shell script text executable
/usr/bin/f-spot-import:                           Bourne-Again shell script text executable
/usr/bin/lcf:                                     Bourne-Again shell script text executable
/usr/bin/ldd:                                     Bourne-Again shell script text executable
/usr/bin/net-snmp-config:                         Bourne-Again shell script text executable
/usr/bin/rarian-sk-config:                        Bourne-Again shell script text executable
/usr/bin/rarian-sk-extract:                       Bourne-Again shell script text executable
/usr/bin/rarian-sk-rebuild:                       Bourne-Again shell script text executable
/usr/bin/rarian-sk-update:                        Bourne-Again shell script text executable
/usr/bin/startx:                                  Bourne-Again shell script text executable
/usr/bin/tzselect:                                Bourne-Again shell script text executable
/usr/bin/ucf:                                     Bourne-Again shell script text executable
/usr/bin/ucfr:                                    Bourne-Again shell script text executable
/usr/bin/usb-devices:                             Bourne-Again shell script text executable
/usr/bin/vm-support:                              Bourne-Again shell script text executable
root@ubuntu:~/resource/shell-study/0622-2013# 
一个稍难的实例,这里如果是初学者,建议你先别研究这一部分
#!/bin/bash
# strip-comment.sh: 去掉C程序中的注释(/* 注释 */).

E_NOARGS=0
E_ARGERROR=66
E_WRONG_FILE_TYPE=67

if [ $# -eq "$E_NOARGS" ]
then
  echo "Usage: `basename $0` C-program-file" >&2 # 将错误消息发到stderr.
  exit $E_ARGERROR
fi

# 检查文件类型是否正确.
type=`file $1 | awk '{ print $2, $3, $4, $5 }'`
# "file $1" echo出文件类型 . . .
# 然后awk会删掉第一个域, 就是文件名 . . .
# 然后结果将会传递到变量"type"中.
correct_type="ASCII C program text"

if [ "$type" != "$correct_type" ]
then
  echo
  echo "This script works on C program files only."
  echo
  exit $E_WRONG_FILE_TYPE
fi


# 相当隐秘的sed脚本:
#--------
sed '
/^\/\*/d
/.*\*\//d
' $1
#--------
# 如果你花上几个小时来学习sed语法的话, 上边这个命令还是很好理解的.


#  如果注释和代码在同一行上, 上边的脚本就不行了.
#+ 所以需要添加一些代码来处理这种情况.
#  这是一个很重要的练习.

#  当然, 上边的代码也会删除带有"*/"的非注释行 --
#+ 这也不是一个令人满意的结果.

exit 0


# ----------------------------------------------------------------
# 下边的代码不会执行, 因为上边已经'exit 0'了.

# Stephane Chazelas建议使用下边的方法:

usage() {
  echo "Usage: `basename $0` C-program-file" >&2
  exit 1
}

WEIRD=`echo -n -e '\377'`   # 或者WEIRD=$'\377'
[[ $# -eq 1 ]] || usage
case `file "$1"` in
  *"C program text"*) sed -e "s%/\*%${WEIRD}%g;s%\*/%${WEIRD}%g" "$1" \
     | tr '\377\n' '\n\377' \
     | sed -ne 'p;n' \
     | tr -d '\n' | tr '\377' '\n';;
  *) usage;;
esac

#  如果是下列的这些情况, 还是很糟糕:
#  printf("/*");
#  或者
#  /*  /* buggy embedded comment */
#
#  为了处理上边所有这些特殊情况(字符串中的注释, 含有 \", \\" ...
#+ 的字符串中的注释)唯一的方法还是写一个C分析器
#+ (或许可以使用lex或者yacc?).

exit 0

which

which command-xxx将会给出"command-xxx"的完整路径. 当你想在系统中准确定位一个特定的命令或工具的时候, 这个命令就非常有用了.

root@ubuntu:~/resource/shell-study/0622-2013# which which
/usr/bin/which
root@ubuntu:~/resource/shell-study/0622-2013# 

whereis

与上边的which很相似, whereis command-xxx不只会给出"command-xxx"的完整路径, 而且还会给出这个命令的man页的完整路径.

root@ubuntu:~/resource/shell-study/0622-2013# whereis which
which: /bin/which /usr/bin/which /usr/share/man/man1/which.1.gz
root@ubuntu:~/resource/shell-study/0622-2013# 

whatis

whatis filexxx将会在whatis数据库中查询"filexxx". 当你想确认系统命令和重要的配置文件的时候, 这个命令就非常重要了. 可以把这个命令认为是一个简单的man命令.

root@ubuntu:~/resource/shell-study/0622-2013# whatis which
which (1)            - locate a command
root@ubuntu:~/resource/shell-study/0622-2013# 

来看一个实例

#!/bin/bash

# 所有在/usr/bin中的神秘2进制文件都是些什么东西?

DIRECTORY="/usr/bin"

for file in $DIRECTORY/*
do
  whatis `basename $file`   # 将会echo出这个2进制文件的信息.
done

exit 0

# 你可能希望将这个脚本的输出重定向, 像这样:
# ./sh >>whatis.db
# 或者一页一页的在stdout上察看,
# ./sh | less
结果:
root@ubuntu:~/resource/shell-study/0622-2013# ./test3.sh 
[ (1)                - check file types and compare values
2to3: nothing appropriate.
2to3-2.6: nothing appropriate.
a2p (1)              - Awk to Perl translator
abrowser: nothing appropriate.
aconnect (1)         - ALSA sequencer connection manager
acpi_fakekey (1)     - acpi event wrapper
acpi_listen (8)      - ACPI event listener
add-apt-repository (1) - Adds a repository into the /etc/apt/sources.list or /etc/apt/sources.list.d
addpart (8)          - simple wrapper around the "add partition" ioctl
addr2line (1)        - convert addresses into file names and line numbers.
alacarte (1)         - edit freedesktop.org menus
alsamixer (1)        - soundcard mixer for ALSA soundcard driver, with ncurses interface
amidi (1)            - read from and write to ALSA RawMIDI ports
amixer (1)           - command-line mixer for ALSA soundcard driver
......
vdir

显示详细的目录列表. 与ls -l的效果相似.

root@ubuntu:~/resource/shell-study/0622-2013# ls
test1.sh  test2.sh  test3.sh
root@ubuntu:~/resource/shell-study/0622-2013# vdir
total 12
-rwxr-xr-x 1 root root 700 2013-06-21 17:39 test1.sh
-rwxr-xr-x 1 root root 179 2013-06-21 18:05 test2.sh
-rwxr-xr-x 1 root root 357 2013-06-21 18:21 test3.sh
root@ubuntu:~/resource/shell-study/0622-2013# 

locate, slocate

locate命令将会在预先建立好的档案数据库中查询文件. slocate命令是locate的安全版本(locate命令很有可能已经被关联到slocate命令上了).
$bash locate hickson
/usr/lib/xephem/catalogs/hickson.edb

readlink

显示符号链接所指向的文件.

root@ubuntu:~/resource/shell-study/0622-2013# readlink /usr/bin/awk 
/etc/alternatives/awk
root@ubuntu:~/resource/shell-study/0622-2013# 

strings

使用strings命令在二进制或数据文件中找出可打印字符. 它将在目标文件中列出所有找到的可打印字符的序列. 这个命令对于想进行快速查找n个字符的打印检查来说是很方便的, 也可以用来检查一个未知格式的图片文件(strings image-file | more可能会搜索出像JFIF这样的字符串, 那么这就意味着这个文件是一个jpeg格式的图片文件). 在脚本中, 你可能会使用grep或者sed命令来分析strings命令的输出.

实例:一个"改进过"的strings命令
#!/bin/bash
#
#  这个脚本将会通过排除标准单词列表的形式
#+ 来过滤"strings"命令的输出.
#  这将有效的过滤掉无意义的字符,
#+ 并且只会输出可以识别的字符.

# ===========================================================
#                 脚本参数的标准检查
ARGS=1
E_BADARGS=65
E_NOFILE=66

if [ $# -ne $ARGS ]
then
  echo "Usage: `basename $0` filename"
  exit $E_BADARGS
fi

if [ ! -f "$1" ]                      # 检查文件是否存在.
then
    echo "File \"$1\" does not exist."
    exit $E_NOFILE
fi
# ===========================================================


MINSTRLEN=3                           #  最小的字符串长度.
WORDFILE=/usr/share/dict/words  #  字典文件.
#  也可以指定一个不同的单词列表文件,
#+ 但这种文件必须是以每个单词一行的方式进行保存.


wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`

#  将'strings'命令的输出通过管道传递到多个'tr'命令中.
#  "tr A-Z a-z" 全部转换为小写字符.
#  "tr '[:space:]'" 转换空白字符为多个Z.
#  "tr -cs '[:alpha:]' Z" 将非字母表字符转换为多个Z,
#+ 然后去除多个连续的Z.
#  "tr -s '\173-\377' Z" 把所有z后边的字符都转换为Z.
#+ 并且去除多余重复的Z.
#+ (注意173(123 ascii "{")和377(255 ascii 最后一个字符)都是8进制)
#+ 这样处理之后, 我们所有之前需要处理的令我们头痛的字符
#+ 就全都转换为字符Z了.
#  最后"tr Z ' '" 将把所有的Z都转换为空格,
#+ 这样我们在下边循环中用到的变量wlist中的内容就全部以空格分隔了.

#  ****************************************************************
#  注意, 我们使用管道来将多个'tr'的输出传递到下一个'tr'时
#+ 每次都使用了不同的参数.
#  ****************************************************************


for word in $wlist                    # 重要:
                                      # $wlist 这里不能使用双引号.
                                      # "$wlist" 不能正常工作.
                                      # 为什么不行?
do

  strlen=${#word}                     # 字符串长度.
  if [ "$strlen" -lt "$MINSTRLEN" ]   # 跳过短的字符串.
  then
    continue
  fi

  grep -Fw $word "$WORDFILE"          #  只匹配整个单词.
#      ^^^                            #  "固定字符串" 和
                                      #+ "整个单词" 选项.

done


exit $?
结果:
root@ubuntu:~/resource/shell-study/0622-2013# cat test1.sh 
#!/bin/bash

# 使用cpio来拷贝目录树.

# 使用'cpio'的优点:
#   加速拷贝. 比通过管道使用'tar'命令快一些.
#   很适合拷贝一些'cp'命令
#+  搞不定的的特殊文件(比如名字叫pipes的文件, 等等)

ARGS=2
E_BADARGS=65

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` source destination"
  exit $E_BADARGS
fi

source=$1
destination=$2


find "$source" -depth | cpio -admvp "$destination"
#               ^^^^^         ^^^^^
# 阅读'find'和'cpio'的man页来了解这些选项的意义.


# 练习:
# -----

#  添加一些代码来检查'find | cpio'管道命令的退出码($?)
#+ 并且如果出现错误的时候输出合适的错误码.

exit 0
root@ubuntu:~/resource/shell-study/0622-2013# ./test4.sh test
test1.sh  test2.sh  test3.sh  test4.sh  
root@ubuntu:~/resource/shell-study/0622-2013# ./test4.sh test1.sh 
bin
bin's
bash
tar
tar's
pipes
then
echo
echo's
usage
usage's
source
source's
destination
destination's
exit
exit's
source
source's
destination
destination's
find
source
source's
depth
depth's
destination
destination's
find
find
exit
exit's
root@ubuntu:~/resource/shell-study/0622-2013#

先到这里了,O(∩_∩)O~

我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html

待续。。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值