Bash
如何使用文件名參數或預設為標準輸入、標準輸出(簡要)
我想以更簡潔、更靈活的方式將文件名作為 bash 腳本中的參數處理,輸入和輸出文件名採用 0、1 或 2 個參數。
- 當 args = 0 時,從標準輸入讀取,寫入標準輸出
- 當 args = 1 時,從 $1 讀取,寫入 stdout
- 當 args = 2 時,從 $ 1, write to $ 2
如何使 bash 腳本版本更簡潔、更短?
這是我現在所擁有的,它有效,但不干淨,
#!/bin/bash if [ $# -eq 0 ] ; then #echo "args 0" fgrep -v "stuff" elif [ $# -eq 1 ] ; then #echo "args 1" f1=${1:-"null"} if [ ! -f $f1 ]; then echo "file $f1 dne"; exit 1; fi fgrep -v "stuff" $f1 elif [ $# -eq 2 ]; then #echo "args 2" f1=${1:-"null"} if [ ! -f $f1 ]; then echo "file $f1 dne"; exit 1; fi f2=${2:-"null"} fgrep -v "stuff" $f1 > $f2 fi
perl 版本更乾淨,
#!/bin/env perl use strict; use warnings; my $f1=$ARGV[0]||"-"; my $f2=$ARGV[1]||"-"; my ($fh, $ofh); open($fh,"<$f1") or die "file $f1 failed"; open($ofh,">$f2") or die "file $f2 failed"; while(<$fh>) { if( !($_ =~ /stuff/) ) { print $ofh "$_"; } }
我會更多地使用I/O 重定向:
#!/bin/bash [[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1 [[ $1 ]] && exec 3<$1 || exec 3<&0 [[ $2 ]] && exec 4>$2 || exec 4>&1 fgrep -v "stuff" <&3 >&4
解釋
[[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1
測試是否已將輸入文件指定為命令行參數以及該文件是否存在。
[[ $1 ]] && exec 3<$1 || exec 3<&0
如果
$1
設置了,即指定了輸入文件,則指定文件在文件描述符處打開3
,否則stdin
在文件描述符處重複3
。
[[ $2 ]] && exec 4>$2 || exec 4>&1
類似地,如果
$2
設置了,即指定了輸出文件,則指定文件在文件描述符處打開4
,否則stdout
在文件描述符處重複4
。
fgrep -v "stuff" <&3 >&4
最後
fgrep
被呼叫,將其stdin
和重定向stdout
到先前設置的文件描述符3
和4
分別。重新打開標準輸入和輸出
如果您不想打開中間文件描述符,另一種方法是直接用指定的輸入和輸出文件
stdin
替換對應的文件描述符:stdout
#!/bin/bash [[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1 [[ $1 ]] && exec 0<$1 [[ $2 ]] && exec 1>$2 fgrep -v "stuff"
這種方法的一個缺點是您失去了將腳本本身的輸出與作為重定向目標的命令的輸出區分開來的能力。在原始方法中,您可以將腳本輸出定向到未修改的
stdin
andstdout
,而後者又可能被腳本的呼叫者重定向。指定的輸入和輸出文件仍然可以通過相應的文件描述符訪問,這與腳本stdin
和stdout
.