2017-04-10 56 views
1

作爲系統管理員,我必須在具有不同鍵盤佈局的不同服務器上工作。所以每當我遇到很大的問題,如'&','|'。BASH:將特殊符號分配給變量

有沒有什麼辦法可以將這些符號分配給一個變量,並在需要符號時調用該變量?

例如:假定

echo "|" > filename 
pipe = $(cat filename) 

ps -ef somethinghere($(pipe)) grep java 

應該給我運行的Java程序。我盡我所能,但失敗了。

請幫忙。

+1

更改鍵盤佈局不是更容易嗎? – Derlin

+0

@ Derlin no。來自相同區域的其他用戶可能使用相同的用戶信用。 –

+0

這不起作用,因爲**數據**不被解析爲**語法** - 如果是,處理敵對數據(比如說一個名爲'/ tmp/$(rm -rf $ HOME)'的文件)幾乎是不可能的。 –

回答

2

如果你真的想這樣做,這裏是一個辦法:

pipe="|" 
eval $(echo ps -ef $pipe grep java) 

與貓:

eval $(echo ps -ef $(cat pipe.txt) grep java) 

注意,使用eval氣餒,並且該命令將成爲問題,只要你需要複雜的命令,包括引號,轉義序列,文件名和/或空格參數等。

在我看來,最好是讓你熟悉y與我們如何改變不同的Linux系統上的鍵盤佈局(例如參見loadkeys)。

+1

這適用於非常有限的情況。開始使用空格處理文件名;需要引用的命令;等等,它會很快分解。 –

+0

...作爲一個稍微不太成問題的變體,「eval」ps -ef $ pipe grep java「'至少*顯式*關於它在做什麼(生成一個單獨的字符串,它被評估爲代碼),使相關的副作用對讀者來說更加明顯(因此,當添加更多單詞時,需要使用文字而不是語法引號,即''eval「ps -ef $ pipe grep \」java -Xmx \「」'')。 –

3

下面的函數將做的工作:

# read a number of arguments on the left-hand side; those actual arguments; then the RHS 
pipe() { 
    local nargs 
    local -a firstCmd 

    nargs=$1; shift 
    firstCmd=() 
    for ((i=0; i<nargs; i++)); do 
    firstCmd+=("$1"); shift 
    done 
    "${firstCmd[@]}" | "[email protected]" 
} 

# basic use case 
pipe 3 ps -ef somethinghere grep java 

# or, for a pipeline with more than two components: 
pipe 3 ps -ef somethinghere pipe 2 grep java tee log.txt 

更棒的是,不像使用eval的解決方案,它甚至會用更復雜的值工作:

pipe 3 ps -ef 'something with spaces here' grep java 

人們可以還寫了一個使用sigil值的函數版本:

pipe() { 
    local sigil 
    local -a firstCmd 

    sigil=$1; shift 
    firstCmd=() 
    while (($#)); do 
    if [[ $1 = "$sigil" ]]; then 
     shift 
     "${firstCmd[@]}" | pipe "$sigil" "[email protected]" 
     return 
    else 
     firstCmd+=("$1") 
     shift 
    fi 
    done 
    "${firstCmd[@]}" 
} 

在這種情況下,你甚至可以這樣做:

sigil=$(uuidgen) # generate a random, per-session value 
pipe "$sigil" ps -ef 'something with spaces here' "$sigil" grep java "$sigil" tee log.txt 
+0

您是否遇到過像「pipe(){」$ {@:2:$ 1} | | 「$ {@:$(($ 1 + 2))}」; }'?我認爲這相當於你的第一個提議的解決方案。有點神祕,也許... – Fred

+0

合理,但我寧願詳細和可讀的代碼。如果您想提供精簡版作爲單獨的答案,請隨意。 –

1

建立在相同的邏輯,通過CharlesDuffy提出的第一個解決方案,這應該是等價的:

pipe() 
{ 
    "${@:2:$1}" | "${@:$(($1+2))}" 
} 

而不是使用迭代建立一個帶有第一個命令和移位參數的數組,直到剩下的只包含第二個命令,該解決方案使用擴展。

  • "${@:2:$1}"膨脹$1參數,起始於位置2
  • "${@:$(($1+2))}"擴展所有參數起始於位置$1 + 2.

在這兩種情況下,雙引號確保參數作爲參數每一個字擴大(不會執行分詞)。因爲可讀性(對於那些有一天需要維護代碼的打算的編碼者)可能會勝過任何優勢。如果你覺得這太神祕了,隨時可以避免它。