用 cat 進行拼接
文件查找與文件列表
玩轉 xargs
用 tr 進行轉換
排序
臨時文件命名與隨機數
分割文件和數據
根據擴展名切分文件名
mv 批量重命名文件
交互輸入自動化
cat:
echo 'Text through stdin' | cat - file.txt # - 被作為 stdin 文本的文件名。 $ cat -s file #壓縮相鄰的空白行 $ cat -T file.py #將制表符顯示為^I $ cat -n lines.txt #顯示行號
find:
$ find . -print
$ find .
這兩條命令效果是一樣的。都是查找當前目錄下的所有的文件及目錄,使用-print時‘\n’作為用於輸出的文件名進行分隔,-print0 指明了使用‘\0’ 進行分隔。
$ find /home/slynux -name "*.txt" -print #按文件名查找 $ find . -iname "example*" -print #按文件名不區分大小寫查找 $ find . \( -name "*.txt" -o -name "*.pdf" \) -print # -o OR條件 ()將括號中的語句作為一個整體
$ find /home/users -path "*/slynux/*" -print # -name 用給定的文件名匹配,-path將文件路徑作為一個整體進行匹配。
$ find . -regex ".*\(\.py\|\.sh\)$" #正則表達式 查找.py或.sh文件
$ find . -iregex ".*\(\.py\|\.sh\)$" #不區分大小寫
$ find . ! -name "*.txt" -print # !否定。不已.txt結尾的文件
$ find . -maxdepth 1 -name "f*" -print #基於目錄的深度查找 -maxdepth -mindepth
在有 -maxdepth 或 -mindepth時,這兩個參數應該作為第三個參數出現。如果作為第4個或之后的參數,就可能會影響到 find 的效率,因為它不得不進行一些不必要的檢查。例如,如果 -maxdepth 作為第四個參數, -type 作為第三個參數, find首先會找出符合 -type 的所有文件,然后在所有匹配的文件中再找出符合指定深度的那些。但是如果反過來,目錄深度作為第三個參數, -type 作為第四個參數,那么 find 就能夠在找到所有符合指定深度的文件后,再檢查這些文件的類型,這才是最有效的搜索之道。
-type 按類型查找
文件類型 類型參數
普通文件 f
符號鏈接 l
目錄 d
字符設備 c
塊設備 b
套接字 s
FIFO p
$ find . -type d -print #列出所有的目錄
Unix/linux文件系統中每個文件都有三種時間戳:
訪問時間( -atime ):用戶最近一次訪問文件的時間。
修改時間( -mtime ):文件內容最后一次被修改的時間。
變化時間( -ctime ):文件元數據(例如權限或所有權)最后一次改變的時間。
-atime 、 -mtime 、 -ctime 可作為 find 的時間選項。它們可以用整數值指定,單位是天。這些整數值通常還帶有 - 或 + : - 表示小於, + 表示大於。
$ find . -type f -atime -7 -print #打印出在最近7天內被訪問過的所有文件
$ find . -type f -atime 7 -print #打印出恰好在7天前被訪問過的所有文件
$ find . -type f -atime +7 -print #打印出訪問時間超過7天的所有文件
-amin (訪問時間),-mmin (修改時間),-cmin (變化時間) 這些時間的計量單位是“ 分鍾 ”。
使用 -newer ,我們可以指定一個用於比較時間戳的參考文件,然后找出比參考文件更新的(更近的修改時間)所有文件
$ find . -type f -newer file.txt -print #找出比file.txt修改時間更近的所有文件
基於文件大小的搜索:-size
$ find . -type f -size +2k # 大於2KB的文件
- b —— 塊(512字節)
- c —— 字節。
- w —— 字(2字節)
- k —— 1024字節
- M —— 1024K字節
- G —— 1024M字節
$ find . -type f -name "*.swp" -delete #刪除匹配的文件:
$ find . -type f -perm 644 -print # 打印出權限為644的文件
$ find . -type f -user fzk -print #打印出用戶fzk擁有的文件
# find . -type f -user root -exec chown fzk {} \;
#找到root用戶的文件,執行chown fzk {},這里{}會替換成相應的文件。如果找到1.txt,2.txt。
它會被解析為 chown fzk test1.txt 和 chown fzk test2.txt。相當於兩條命令
想在一條命令中修改一個列表的文件,在exec中使用+來代替
$ find . -type f -name "*.c" -exec cat {} \;>all_c_files.txt #找到所有c文件,寫入到單一文件
跳過指定的目錄:
$ find devel/source_path \( -name ".git" -prune \) -o \( -type f -print \)
以上命令打印出不包括在.git目錄中的所有文件的名稱(路徑)。\( -name ".git" -prune \) 的作用是用於進行排除,它指明了 .git目錄應該被排除在外,而 \( -type f -print \) 指明了需要執行的動作。這些動作需要被放置在第二個語句塊中(打印出所有文件的名稱和路徑)。
xargs:
xargs 能夠處理 stdin 並將其轉換為特定命令的命令行參數。 xargs 也可以將單行或多行文本輸入轉換成其他格式,例如單行變多行或是多行變單行。
$ cat example.txt | xargs #多行變單行
1 2 3 4 5 6 $ echo 1 2 3 4 5 6 | xargs -n 3 #單行變多行
1 2 3
4 5 6
$ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2
split split
split split
$ find . -type f -name "*.txt" -print0 | xargs -0 rm -f
找到所有.txt刪掉。如果用這條命令 find . -type f -name "*.txt" -print | xargs rm -f 文件中的空格會當做文件的分隔符,最后不知道都會刪掉什么,-print0 已字符null('\0')來分隔輸出,xargs -0 將\0 作為輸入定界符。
tr:tr 可以對來自標准輸入的內容進行字符替換、字符刪除以及重復字符壓縮。它可以將一組字符變成另一組字符,因而通常也被稱為轉換(translate)命令。
$ echo "HELLO WHO IS THIS" | tr 'A-Z' 'a-z' hello who is this
$ echo "Hello 123 world 456" | tr -d '0-9' #-d 刪除字符
Hello world
$ echo hello 1 char 2 next 4 | tr -d -c '0-9 \n' #-c 補集,刪掉除了0-9 空格 換行符的其他字符,也就是只留下這些字符
1 2 4
$ echo "GNU is not UNIX. Recursive right ? | tr -s ' ' #刪掉重復的‘ ’
GNU is not UNIX. Recursive right ?
排序:sort
$ sort file1.txt file2.txt > sorted.txt $ sort -n file.txt #按照數字進行排序 $ sort -r file.txt #按照逆序進行排序 $ sort -M months.txt #按照月份進行排序(依照一月,二月,三月......) $ sort -m sorted1 sorted2 #合並兩個已排序過的文件 $ sort file1.txt file2.txt | uniq #找出已排序文件中不重復的行
臨時文件:
$ filename=`mktemp` #創建了一個臨時文件,並打印出存儲在 $filename 中的文件名。 $ echo $filename /tmp/tmp.8xvhkjF5fH $ dirname=`mktemp -d` #創建了一個臨時目錄,並打印出存儲在 $dirname 中的目錄名。 $ echo $dirname tmp.NI8xzW7VRX $ tmpfile=`mktemp -u` #文件名被存儲在 $tmpfile 中,但並沒有創建對應的文件。 $ echo $tmpfile /tmp/tmp.RsGmilRpcT $mktemp test.XXX #根據模板創建臨時文件名 test.2tc
分隔文件和數據:
$ split -b 10k data.file -d -a 4 x $ ls data.file x0009 x0019 x0029 x0039 x0049 x0059 x0069 x0079
上面的代碼將data.file分隔成每個文件大小是10kb的若干個文件。-d是以數字為后綴(沒有這個參數是字母),10k還可以用M、G、c(byte)、w(word)、l(line 行數)等。-a length指定后綴的長度。最后一個參數PREFIX,前綴,是什么字符前綴就是什么。
假如分隔一個日志文件server.log,將日志分隔成server1.log, server2.log, server3.log
$ cat server.log
SERVER-1
[connection] 192.168.0.1
[connection] 192.168.0.2
[disconnect] 192.168.0.3
[connection] 192.168.0.4
SERVER-2
[connection] 192.168.0.1
[connection] 192.168.0.2
[disconnect] 192.168.0.3
[connection] 192.168.0.4
SERVER-3
[connection] 192.168.0.1
[connection] 192.168.0.2
[disconnect] 192.168.0.3
[connection] 192.168.0.4
$ csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log" ; rm server00.log
$ ls
server01.log server02.log server03.log server.log
csplit 是 split 工具的一個變體。 split 只能夠根據數據大小或行數分割文件,而 csplit可以根據文本自身的特點進行分割。
- /SERVER/ 用來匹配某一行。/[REGEX]/ 表示文本樣式。包括從當前行(第一行)直到(但不包括)包含“ SERVER ”的匹配行。
-
{*} 表示根據匹配重復執行分割,直到文件末尾為止。可以用{整數}的形式來指定分割執行的次數。
- -s 使命令進入靜默模式,不打印其他信息。
- -n 指定分割后的文件名后綴的數字個數,例如01、02、03等
-
-f 指定分割后的文件名前綴(在上面的例子中,server就是前綴)。
-
-b 指定后綴格式。例如 %02d.log ,類似於C語言中 printf 的參數格式。在這里文件名=前綴+后綴= server + %02d.log 。
-
因為分割后的第一個文件沒有任何內容(匹配的單詞就位於文件的第一行中),所以我們刪除了server00.log。
分隔字符串:
$ file_jpg="sample.jpg" $ name=${file_jpg%.*} $ echo File name is: $name
File name is: sample
${VAR%.*} 的含義如下所述:
從 $VAR 中刪除位於 % 右側的通配符(在前例中是. * )所匹配的字符串。通配符從右向左進行匹配。
給 VAR 賦值, VAR=sample.jpg 。那么,通配符從右向左就會匹配到.jpg,因此,從 $VAR中刪除匹配結果,就會得到輸出 sample
% 屬於非貪婪(non-greedy)操作。它從右到左找出匹配通配符的最短結果。還有另一個操作符 %% ,這個操作符與 % 相似,但行為模式卻是貪婪的,這意味着它會匹配符合條件的最長的字符串。
$VAR=hack.fun.book.txt $ echo ${VAR%.*} hack.fun.book $ echo ${VAR%%.*} hack
還有一個:
$ file_jpg="sample.jpg" $ extension=${file_jpg#*.} $ echo Extension is: $extension Extension is: jpg
${VAR#*.} 的含義如下所述:
從 $VAR 中刪除位於 # 右側的通配符(即在前例中使用的 *. )所匹配的字符串。通配符從左向右進行匹配。## 從左向右進行貪婪匹配,並從指定變量中刪除匹配結果。
可能發現了,都是刪除匹配的為什么還要有兩種匹配方式,用${file_jpg%*.}不能代替${file_jpg#*.}嗎?看下面
http="www.sample.com" echo ${http%.com} echo ${http%.co} echo ${http%.*} echo ${http#www.} echo ${http#ww.} echo ${http#*.}
結果:
www.sample
www.sample.com
www.sample
sample.com
www.sample.com
sample.com
可以看出%只能從最右側開始匹配,#只能從最左側開始匹配。
批量重命名移動的例子:運用find和上面的分隔字符串的方法
count=1; for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1` do new=image-$count.${img##*.} echo "Renaming $img to $new" mv "$img" "$new" let count++ done
實現自動交互輸入。
首先有一個運行起來需要你輸入參數的腳本interactive.sh
#!/bin/bash read -p "Enter param1 :" param1; read -p "Enter param2 :" param2; echo "you entered : $param1 $param2"
運行前手動輸入$ echo -e "1\nhello\n" | ./interactive.sh 和 從文本讀取 ./interactive.sh < input.data 都可以實現。
還有一種利用expect來實現。一般的系統中不帶expect包,需要自己下載,我的系統是ubuntu14.04 ,在下載expect前需要下載tcl。ubuntu系統直接運行:
sudo apt-get install tcl tk expect
裝好了后,建一個expect.sh腳本
#!/usr/bin/expect spawn ./interactice.sh expect "Enter param1 :" send "1\n" expect "Enter param2 :" send "2\n" expect eof
輸出:
spawn ./interactive.sh
Enter param1 :1
Enter param2 :2
you entered : 1 2
spwan:指定那個命令需要自動化。expect:提供需要等待的消息。send:等待的消息到達后向終端發送消息。expect eof:命令交互結束。