2009-09-22 53 views
0

假設您要製作bash腳本,該腳本不支持任何選項,但行爲類似cp,因爲系統提供的cp不接受多個源。bash腳本針對最終參數對每個參數執行操作

對於使用該系統的(假設和打破)cp是:

cp source target # target may be a directory 

爲腳本的使用將是:

cp.sh source... target # target must be a directory 

下面是腳本的起點:

#!/bin/bash 
tgt="$1" 
shift 
for src in "[email protected]"; do 
    echo cp $src $tgt 
done 

當運行參數「a b c d」(注意:牛逼d是目標),它輸出:

cp b a 
cp c a 
cp d a 

的目標是修復腳本這個代替輸出,同時保持代碼的簡單:

cp a d 
cp b d 
cp c d 

回答

5

/test.bash源1源2目標1

#!/bin/bash 

target=${!#} 

if [ ! -d $target ] ; then 
    echo "$target must be a directory " >&2 
    exit 1; 
fi 

args=("[email protected]") 
unset args[${#args[@]}-1] 

for src in "${args[@]}"; do 
    echo cp $src $target 
done 

將輸出

cp source1 target1 
cp source2 target1 
+0

我真的很喜歡這個!我在$ target和$ src(用於支持具有空格的路徑)的用法中添加引號,但除此之外,這非常完美。 – 2009-09-22 19:33:16

+0

你應該在'for'循環中添加一個'if [-f「$ src」]'(或'-a')。 – 2009-09-22 20:30:40

1

爲什麼? cp命令已經做到了。做一個人cp,你會看到。

如果你仍然堅持,這裏有兩種方法來獲得最後一個參數。方法1:在陣列位置的命令行,並提取的最後一個元素:

arg=("[email protected]") 
last_arg=${arg[(($# - 1))]} 

第一行放命令行參數到陣列ARG。如果您的命令行包含a b c d,則arg [0] =='a',... argv [3] =='d'。

第二行提取最後一個參數。 (($# - 1))取參數的數量(在這種情況下爲4),從它中減去1(得到3)。該表達式變爲:

last_arg=${arg[3]} 

它指向最後一個參數。


第二種方法不是很便攜,它使用BASH_ARGV變量,它是$ @但是以相反的順序。如果您的命令行是A B C d然後$ {BASH_ARGV [0]} == 'd',... $ {BASH_ARGV [3]} == '一':

last_arg=${BASH_ARGV[0]} 

我希望這有助於。

+0

課程「CP」已經支持這種行爲。但是,我有另一個程序運行,但沒有。 – 2009-09-22 19:26:16

-1

使用該提取的最後一個參數:

EVAL TGT = \ $$#

然後就處理你以同樣的方式,當你打$#剛剛退出循環

這裏的whjole腳本:

eval tgt=\$$# 

for src in [email protected] 
do 
if [ "$src" == "$tgt" ]; 
then 
    exit 
fi 
echo cp $src $tgt 
done 

很簡單,如果你問我!

+0

這種方法擊敗我的手。帽子給你。 – 2009-09-22 18:27:34

+0

當$#被命中時,關於停止的部分需要追蹤循環索引,這一點我不太在意。而'eval'沒有必要,因爲一些其他答案顯示。 – 2009-09-22 19:36:06

+0

你不需要索引,只需將當前值與tgt進行比較即可。當你點擊$#時,退出的意思就是當你達到$的價值時## – ennuikiller 2009-09-22 20:00:56

0
#!/bin/bash 
t=(x "[email protected]") 
i=1; while [ $i -lt $# ]; do 
    echo cp ${t[$i]} ${t[$#]} 
    i=$(($i + 1)) 
done 
+0

不要使用'$ *';它不保留參數中的空格(它會生成額外的參數)。使用'「$ @」' - 幾乎總是。 – 2009-09-25 16:33:52

+0

很確實,我在鏈接命令時總是使用「$ @」,不知道爲什麼我在這裏沒有這樣做...... – DigitalRoss 2009-09-25 19:33:26

1
#!/bin/bash 
tgt="${@: -1}" # get the last parameter 
for src in "[email protected]"; do 
    if [[ $src != $tgt ]]; then 
     echo cp "$src" "$tgt" 
    fi 
done 
+1

不錯,但我更喜歡用「unset」方法去除所用比較的最後一個參數在這裏(想象一下,如果源代碼實際上與這個代碼相同的目標會發生什麼)。 – 2009-09-22 19:34:47

+0

但是你不想聽到這個,是嗎? 「cp:'d'和'd'是相同的文件」 – 2009-09-22 20:18:35

+0

或者「cp:省略目錄'd'」 – 2009-09-22 20:25:46

2

您可以使用數組切片留下了最後的論點:

tgt="${!#}" 
for src in "${@:1:$#-1}"; do 
    cp "$src" "$tgt" 
done 
0

你不需要任何特殊的bash的功能:

 
eval last=\${$#} 
while [ $# -gt 1 ]; do 
    echo "cp $1 $last" 
    shift 
done 
+0

依靠$ 300作爲第300個參數(當有300個參數時)。它不適用於所有Bourne shell(例如,Solaris 10/bin/sh:'set -abcdefghijkl; echo $ 10'生成'a0'而不是'j'。 – 2009-09-25 16:31:50

+0

Korn shell(同樣在Solaris 10上)也是如此。 – 2009-09-25 16:32:48

+0

當然,對於$#> 9,您需要使用$ {N}(例如$ {10},$ {300})。對於Solaris 10,使用ksh,bash,/ bin/sh可以很好地工作。 – Idelic 2009-09-26 04:09:10

0

您可以直接做到這一點,而無需編寫使用xargs的腳本:

echo source1 source2 | tr "\n" "\0" | tr " " "\0" | 
    xargs --verbose -0 -I{} cp {} dest