簡體   English   中英

在awk print中使用bash for loop變量

[英]Using bash for loop variable within awk print

我試圖了解bash和awk中的具體情況:

我想使用awk 二元運算符兩個變量 (空格) 之間的字符串連接作為變量迭代, $i ,在bash for循環中:

$ for i in ' '; do 
  echo "foo bar" | awk '{print $1$i$2}'
done
foofoo barbar

預期產量為: foobar

問題1

  • 到底是怎么回事? 答案 (標記為正確)

問題2

  • 如何在上面的bash for循環中使用awk來使用字符串連接? 回答

參考

$ $SHELL --version | head -n1
GNU bash, version 4.3.42(4)-release (x86_64-unknown-cygwin)

$ awk --version | head -n1
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.3, GNU MP 6.1.0)

全面測試

$ for i in '+' '-' '*' '/' '%' ' ' ''; do echo "2.0 4.0" | awk '{print $1$i$2}'; done
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0

這似乎有點棘手。 實際上它打印foofoo barbar 因為i的值沒有在定義(它是一個變量),所以它被認為是$0 (我不知道這種行為,但它有意義)。

稍微改變一下代碼

for i in ' '; do 
  echo "foo bar" | awk '{print $1"<"$i">"$2}'
done

輸出:

foo<foo bar>bar

如果要傳遞變量i的值,可以使用-v參數。 $i不會起作用,因為i的值應該是$i的數字,所以只需使用簡單的i

for i in ' '; do
  echo "foo bar" | awk -v i="$i" '{print $1"<"i">"$2}'
done

輸出:

foo< >bar

我試着把它作為評論,但是說的太多了,有些需要格式化:

@adam你似乎對awk有一些根本的誤解,這讓你難以理解你被告知的內容。 我懷疑它歸結為此 - awk不是shell Awk是一個完全獨立的工具/語言,它有自己的范圍,變量,函數等。

不要試圖通過使用中間單引號(例如awk '{print $1'"$i"'$2}' )直接在awk腳本中訪問shell變量的值,因為這會將shell變量的值轉換為解釋器之前的awk代碼讀取它並使用各種值$i打開你的隱藏錯誤消息(或者更糟糕的是 - 沒有錯誤消息的陰險錯誤)的可怕錯誤。

你說你Cannot get -v to work even without for loop:但是你表明它完美地工作了兩次:

$ echo "foo bar" | awk -v var=" " '{print $1var$2}'
foo bar

在上面的例子中,您將創建一個名為var的awk變量,其中包含一個空白字符" " 然后打印$ 1( foo ),然后是var( " " ),然后是$ 2( bar ),輸出<foo>< ><bar>完全應該是這樣。

在所有示例中,您將變量設置為單個空格字符,將其與其他一些值連接(例如-v var=" "然后$1var$2 )然后由於某種原因期望空格字符不存在於輸出。

$ echo "foo bar" | awk -v var=" " '{print $1'var'$2}'
foo bar

在上面的例子中,您將創建一個名為var的awk變量,其中包含一個空白字符" " 當你編寫任何用單引號括起來的shell腳本(awk,sed,grep等)時:

any_cmd 'abc'

然后你告訴cmd解釋/執行符號引號內的內容。 不能在單引號分隔的腳本中包含單引號 - 這是shell基礎。 所以當你寫:

any_cmd 'abc'def'ghi'

內部單引號實際上是從any_cmd語言中any_cmd並返回到shell來解釋,並且shell會在any_cmd之前嘗試擴展它。 所以如果你有:

xyz=17
any_cmd 'abc'$xyz'ghi'

然后any_cmd實際看到的解釋是:

any_cmd 'abc17ghi'

但如果你在那里有東西,shell無法擴展,那么它就會保持原樣:

and_cmd 'abc'def'ghi'

傳遞給any_cmd

any_cmd 'abcdefghi'

回到你的例子:

$ echo "foo bar" | awk -v var=" " '{print $1'var'$2}'
foo bar

var $ 1和$ 2之間將通過外殼以來的第一解釋'圍繞IT方面正在它的awk腳本,回到殼,但那么它只是一些文字,外殼無法展開,因此上方通過awk as-is使它成為:

$ echo "foo bar" | awk -v var=" " '{print $1var$2}'

然后以迂回的方式返回到您的第一個腳本,並再次按預期輸出。

以上聽起來很復雜,但實際上非常簡單:

要在awk中連接字符串,只需將它們並排放置即可。

要將shell變量的值傳遞給awk,請使用-v ,例如awk -v awkvar="$shellvar" 'print "foo" awkvar "bar"'

不要試圖通過反復試驗來學習awk,而是首先閱讀Arnold Robbins的書“Effective Awk Programming”,第4版,然后再玩它。

啊,我想出了問題2

循環初始化:

$ for i in ' '; do echo "foo bar" | awk '{print $1$i$2}'; done
foofoo barbar

探索:引用

$i括在"
'{print $1$i$2}'
'{print $1"$i"$2}'

$ for i in ' '; do echo "foo bar" | awk '{print $1"$i"$2}'; done
foo$ibar

解決方案:引用

這導致我試圖用'所以$i可以正確評估來分解awk:
'{print $1"$i"$2}'
'{print $1'"$i"'$2}'

$ for i in ' '; do echo "foo bar" | awk '{print $1'"$i"'$2}'; done
foobar

測試方案

使用解決方案測試所有awk二元運算符和null:

$ for i in '+' '-' '*' '/' '%' ' ' ''; do 
    echo "2.0 4.0" | awk '{print "Using binary operator \"'"$i"'\" for \""$1"\" and \""$2"\" evaluates to:\t" $1'"$i"'$2}'; 
  done
Using binary operator "+" for "2.0" and "4.0" evaluates to:     6
Using binary operator "-" for "2.0" and "4.0" evaluates to:     -2
Using binary operator "*" for "2.0" and "4.0" evaluates to:     8
Using binary operator "/" for "2.0" and "4.0" evaluates to:     0.5
Using binary operator "%" for "2.0" and "4.0" evaluates to:     2
Using binary operator " " for "2.0" and "4.0" evaluates to:     2.04.0
Using binary operator "" for "2.0" and "4.0" evaluates to:      2.04.0

注意: ''顯然不是二元運算符,只是一個檢查。

成功!

警告:正如其他人所指出的,此解決方案不適用於一般字符串連接 shell變量i應該只是awk二元運算符。 i設置為任何其他變量可能會導致問題。

探索: -v

使用-v似乎不允許二進制操作:

$ echo "2.0 4.0" | awk -v var="+" '{print $1var$2}'
2.0+4.0

輸出: 2.0+4.0
期望的輸出: 6

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM