2012-07-25 192 views
21

我想遍歷從echo $VARIABLE命令獲取的路徑列表。循環遍歷Bash中的路徑變量的元素

例如:

echo $MANPATH將返回

/usr/lib:/usr/sfw/lib:/usr/info

所以這是三個不同的路徑,每個用冒號隔開。我想循環每個路徑。有沒有辦法做到這一點?謝謝。

感謝所有迄今爲止的回覆,看起來我實際上並不需要循環。我只需要一種方法去除冒號,這樣我就可以在這三條路徑上運行一條ls命令。

回答

15

您可以使用Bash的模式替換parameter expansion來填充您的循環變量。例如:

MANPATH=/usr/lib:/usr/sfw/lib:/usr/info 

# Replace colons with spaces to create list. 
for path in ${MANPATH//:/ }; do 
    echo "$path" 
done 

注意:不要將替換擴展放在引號中。您希望來自MANPATH的擴展值被for循環解釋爲單獨的單詞,而不是單個字符串。

+5

如果它們包含空格呢? – 2015-01-07 16:06:54

+7

據我瞭解,當任何子字符串包含空格時,這不起作用,這正是$ PATH使用非空格分隔符的原因。 @ choroba的答案在這方面是正確的。 – intelfx 2015-03-25 08:38:08

+1

@intelfx:問題被標記爲[tag:linux]。如果你在Linux上的* MANPATH *中有空格,那麼你在做Linux錯誤。證明完畢 – 2015-03-25 14:12:46

0

可以使用Bash對X在$ {}符號來實現:

for p in ${PATH//:/$'\n'} ; do 
    echo $p; 
done 
+3

這不處理空格。 – codeforester 2017-05-30 19:40:36

39

可以設置內部字段分隔符:

(IFS=: 
    for p in $MANPATH; do 
     echo "$p" 
    done 
) 

我用了一個子shell所以在IFS的變化沒有反映在我目前的shell中。

+6

我相信即使$ MANPATH包含空格,這也是可行的。 – user1277476 2012-07-25 20:01:14

+3

是的!這是與包含空白的路徑(或任何IFS在您的系統上)一致的唯一答案。經過Cygwin,Fedora,Ubuntu測試,並在$ PATH上爲我工作 – hobs 2013-09-26 15:37:13

+1

處理空間不錯,但不處理glob字符。 – codeforester 2017-05-30 20:36:35

0
for p in $(echo $MANPATH | tr ":" " ") ;do 
    echo $p 
done 
+1

-1用於未加引號的變量插值,不希望的'echo'以及當shell可以執行替換時的子進程。 – tripleee 2012-07-25 18:43:22

+2

它需要引號,但它比殼體內置的線路噪聲更具可讀性。詭計不是敵人。 – user1277476 2012-07-25 20:00:02

+0

這不能通過加引號來解決(只),它至少還有一個@tripleee沒有提及的其他問題。請參閱[爲什麼printf比回顯更好?](https://unix.stackexchange.com/q/65803)。然而,目前非常低的分數看起來很苛刻,因爲它在功能上並不比公認的「解決方案」差得多。 – pjh 2017-08-24 16:36:10

9

的規範辦法做到這一點,在Bash中,是使用read內置適當:

IFS=: read -r -d '' -a path_array < <(printf '%s:\0' "$MANPATH") 

這是唯一可靠的解決方案:將不正是你想要的東西:對分割字符串分隔符:,並且對於空格,換行符和全局字符(如*[ ]等)(與其他答案不同,它們全部斷開)是安全的。

此命令後,你就會有一個數組path_array,並且可以循環就可以了:

for p in "${path_array[@]}"; do 
    printf '%s\n' "$p" 
done 
2

這樣就可以通過$PATH安全去與一個循環,而$IFS將保持在循環內部或外部相同。

while IFS=: read -d: -r path; do # `$IFS` is only set for the `read` command 
    echo $path 
done <<< "${PATH:+"${PATH}:"}" # append an extra ':' if `$PATH` is set 

可以檢查$IFS值,

IFS='xxxxxxxx' 
while IFS=: read -d: -r path; do 
    echo "${IFS}${path}" 
done <<< "${PATH:+"${PATH}:"}" 

和輸出將是這樣的。

xxxxxxxx/usr/local/bin 
xxxxxxxx/usr/bin 
xxxxxxxx/bin 

參考another question on StackExchange

0
IFS=: 
arr=(${MANPATH}) 
for path in "${arr[@]}" ; do # <- quotes required 
    echo $path 
done 

...它確實照顧的空間:O),但也增加了空元素,如果你有這樣的:

:/usr/bin::/usr/lib: 

...那麼指數0,2將是空的(」 「),不能說爲什麼指數4心不是設在所有

+0

這不處理glob字符。 – pjh 2017-08-24 16:46:17

0

這也可以使用Python解決,在命令行:

python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" echo {} 

或者作爲別名:

alias foreachpath="python -c \"import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]\"" 

隨着示例用法:

foreachpath echo {} 

這種方法的優點是,{}將由連續的每條路徑所取代。這可以用來構造各種命令,例如列出目錄中所有文件和目錄的大小(在$PATH中)。包括目錄與在名字空間:

​​

下面是通過在$HOME/.allbin創建符號鏈接到在$PATH每個文件和目錄縮短$PATH變量的長度的示例。這不是爲日常使用是有用的,但是如果你在一個docker容器得到too many arguments錯誤消息,因爲bitbake使用完整$PATH作爲命令行的一部分可以是有用的......

mkdir -p "$HOME/.allbin" 
python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" 'for e in "{}"/*; do ln -sf "$e" "$HOME/.allbin/$(basename $e)"; done' 
export PATH="$HOME/.allbin" 

這應該理論上,還可以加快正常的shell使用和shell腳本,因爲搜索每個執行的命令的路徑更少。它哈哈,雖然,所以我不建議任何人這樣縮短他們的$PATH

但是,foreachpath別名可能派上用場。