[英]How to properly handle wildcard expansion in a bash shell script?
#!/bin/bash
hello()
{
SRC=$1
DEST=$2
for IP in `cat /opt/ankit/configs/machine.configs` ; do
echo $SRC | grep '*' > /dev/null
if test `echo $?` -eq 0 ; then
for STAR in $SRC ; do
echo -en "$IP"
echo -en "\n\t ARG1=$STAR ARG2=$2\n\n"
done
else
echo -en "$IP"
echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
fi
done
}
hello $1 $2
以上是我提供源(SRC)和desitnation(DEST)路徑的shell腳本。 當我沒有放入帶有外卡的SRC路徑時,它工作正常。 當我運行這個shell腳本並給出 '.pdf或'*'時,如下所示:
root@ankit1:~/as_prac# ./test.sh /home/dev/Examples/*.pdf /ankit_test/as
我得到以下輸出:
192.168.1.6
ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/home/dev/Examples/case_howard_county_library.pdf
DEST是/ ankit_test / as,但由於'*',DEST也會被刪除。 預期的答案是
ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/ankit_test/as
所以,如果你了解我想要做什么,請幫助我解決這個問題。 我會感激你的。
提前致謝!!!
我需要確切地知道我如何在我的程序中逐一使用'* .pdf'而不會打擾DEST。
您的腳本需要更多工作。 即使在逃避通配符后,您也無法獲得預期的答案。 你會得到:
ARG1=/home/dev/Examples/*.pdf ARG2=/ankit__test/as
請嘗試以下方法:
for IP in `cat /opt/ankit/configs/machine.configs`
do
for i in $SRC
do
echo -en "$IP"
echo -en "\n\t ARG1=$i ARG2=$DEST\n\n"
done
done
像這樣運行:
root@ankit1:~/as_prac# ./test.sh "/home/dev/Examples/*.pdf" /ankit__test/as
shell將擴展通配符,除非你將它們轉義,例如,如果你有
$ ls
one.pdf two.pdf three.pdf
並運行您的腳本
./test.sh *.pdf /ankit__test/as
它會是一樣的
./test.sh one.pdf two.pdf three.pdf /ankit__test/as
這不是你所期望的。 干
./test.sh \*.pdf /ankit__test/as
應該管用。
如果可以,請更改傳遞給shell腳本的參數的順序,如下所示:
./test.sh /ankit_test/as /home/dev/Examples/*.pdf
這將使您的生活變得更加容易,因為變量部分移動到行尾。 然后,以下腳本將執行您想要的操作:
#!/bin/bash
hello()
{
SRC=$1
DEST=$2
for IP in `cat /opt/ankit/configs/machine.configs` ; do
echo -en "$IP"
echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
done
}
arg2=$1
shift
while [[ "$1" != "" ]] ; do
hello $1 $arg2
shift
done
對於使用通配符(如* .txt)的多個輸入文件,我發現這可以完美地工作,不需要轉義。 它應該像本機bash應用程序一樣工作,如“ls”或“rm”。 這在任何地方都沒有記錄,所以因為我花了3天的時間來試圖找出它,所以我決定將它發布給未來的讀者。
目錄包含以下文件(ls的輸出)
file1.txt file2.txt file3.txt
像運行腳本一樣
$ ./script.sh *.txt
甚至喜歡
$ ./script.sh file{1..3}.txt
劇本
#!/bin/bash
# store default IFS, we need to temporarily change this
sfi=$IFS
#set IFS to $'\n\' - new line
IFS=$'\n'
if [[ -z $@ ]]
then
echo "Error: Missing required argument"
echo
exit 1
fi
# Put the file glob into an array
file=("$@")
# Now loop through them
for (( i=0 ; i < ${#file[*]} ; i++ ));
do
if [ -w ${file[$i]} ]; then
echo ${file[$i]} " writable"
else
echo ${file[$i]} " NOT writable"
fi
done
# Reset IFS to its default value
IFS=$sfi
輸出
file1.txt writable
file2.txt writable
file3.txt writable
關鍵是暫時切換IFS(內部字段分隔符)。 您必須確保在切換之前存儲它,然后在完成之后將其切換回來,如上所示。
現在,您在文件[]數組中有一個擴展文件列表( 帶有空格轉義 ),然后您可以循環遍歷。 我喜歡這個解決方案最好,最容易為用戶編程和最簡單。
你也錯過了最后的“完成”以關閉你的外部for循環。
好的,這似乎做你想要的:
#!/bin/bash
hello() {
SRC=$1
DEST=$2
while read IP ; do
for FILE in $SRC; do
echo -e "$IP"
echo -e "\tARG1=$FILE ARG2=$DEST\n"
done
done < /tmp/machine.configs
}
hello "$1" $2
hello
函數時,雙引號是必需的,否則僅僅評估$1
事實會導致擴展通配符,但我們不希望在函數中分配$SRC
之前發生這種情況。 這是我想出的:
#!/bin/bash
hello()
{
# DEST will contain the last argument
eval DEST=\$$#
while [ $1 != $DEST ]; do
SRC=$1
for IP in `cat /opt/ankit/configs/machine.configs`; do
echo -en "$IP"
echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
done
shift || break
done
}
hello $*
我們將傳遞腳本獲得的所有參數,而不是僅將兩個參數傳遞給hello()函數。
在hello()函數內部,我們首先將最終參數賦值給DEST var。 然后我們遍歷所有參數,將每個參數分配給SRC,並使用SRC和DEST參數運行我們想要的任何命令。 請注意,如果它們包含空格,您可能需要在$ SRC和$ DEST周圍加上引號。 當SRC與DEST相同時,我們停止循環,因為這意味着我們已經達到最終參數(目標)。
你在跑
./test.sh /home/dev/Examples/*.pdf /ankit_test/as
並且您的交互式shell在腳本獲取之前擴展通配符。 你只需要在啟動它時引用第一個參數,如
./test.sh "/home/dev/Examples/*.pdf" /ankit_test/as
然后,在你的腳本中,引用“$ SRC”,你真正想要帶有通配符的東西(例如,當你做echo $SRC
,而是使用echo "$SRC"
)並在你想要擴展通配符時不加引號。 基本上,除非您希望解釋元字符,否則始終在可能包含shell元字符的內容周圍加上引號。 :)
沒有必要生成一個shell來查看$?
變量,您可以直接評估它。
它應該只是:
if [ $? -eq 0 ]; then
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.