layout: post title: Linux Bash AWK知识汇集 categories:
if [[ $i =~ xyz ]]
/A[^B]B/
实现read a b c < <(echo "23 76 海外 海外" | awk '{print $1,$2,$3}')
第一个<是重定向, <(cmds)
是bash进程替代(Process Substitution),
如果理解什么是命名管道, 那么<(...)
就是一个临时的命名管道;
如果不理解, 可以简单的看作bash产生一个/dev/fdxxx的文件, 文件内容是cmds的标准输出
mkfifo npipe
(echo "a b c d" > npipe)&
read k1 k2 k3 k4 < npipe
此时k1 k2 k3 k4已经分别赋值成a b c d
注意:不能用 |
直接给read变量, 因为echo "a b c d" | read k1 k2 k3 k4
时, read在子shell中执行, 执行结果不能影响父shell.
a=1; [[ $a -eq 1 ]] && echo "1" || { echo 0; exit; }
exit后必须有";", 否则出错
Ijob=$1
echo $Ijob
无输出, 原因未知
echo "" $Ijob
输出
当shell碰到第一个单引号时, 它忽略掉其后直到右引号的所有特殊字符 双引号作用与单引号类似, 区别在于它没有那么严格. 单引号告诉shell忽略所有特殊字符, 而双引号只要求忽略大多数, 具体说, 括在双引号中的三种特殊字符不被忽略:$,\,` ,即双引号会解释字符串的特别意思,而单引号直接使用字符串. 如果使用双引号将字符串赋给变量并反馈它, 实际上与直接反馈变量并无差别. 如果要查询包含空格的字符串, 经常会用到双引号.
x=*
echo $x
hello.sh menus.sh misc.sh phonebook tshift.sh
echo '$x'
$x
echo "$x"
*
这个例子可以看出无引号、单引号和双引号之间的区别.
在最后一种情况中, 双引号告诉shell在引号内照样进行变量名替换, 所以shell把$x替换为, 因为双引号中不做文件名替换, 所以就把作为要显示的值传递给echo.
对于第一种情况需要进一步说明, shell在给变量赋值时不进行文件名替换(这从第三种情况中也能看出来), 各步骤发生的精确次序如下:
这个赋值的先后次序非常重要:shell先作变量替换, 然后作文件名替换, 最后把这行处理为参数
命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置.
shell中有两种方法作命令替换:把shell命令用反引号或者$(...)
结构括起来, 其中, $(...)
格式受到POSIX标准支持, 也利于嵌套.
反斜杠一般用作转义字符, 或称逃脱字符, linux如果echo
要让转义字符发生作用, 就要使用-e选项, 且转义字符要使用双引号
echo -e "\n"
反斜杠的另一种作用,就是当反斜杠用于一行的最后一个字符时, shell把行尾的反斜杠作为续行, 这种结构在分几行输入长命令时经常使用.
sed一般使用单引号,sed引用shell变量时使用双引号即可, 双引号是弱转义,不会去除$的变量表示功能, 而单引号为强转义, 会把$作为一般符号表示, 不会表示为变量.
不可直接使用 var=1+1, 或var=$var+1之类
正确方法
最推荐:((var+=1))
或 let "var+=1"
符合习惯:var=$[$var+1]
或 <code>var=`expr $var + 1`</code>
浮点数计算:最推荐使用bc, <code>var=`echo "$var+1"|bc`</code>
浮点数计算, 使用awk, <code>var=`echo "$var 1" | awk '{printf("%g",$1*$2)}'</code>
除以上常用的3种外, 3-9也可以作为文件描述符, 常被用来作为临时的中间描述符.
实例
command 2>errfile
: command的错误重定向到文件errfile. command 2>&1 | ...
: command的错误重定向到标准输出, 错误和标准输出都通过管道传给下个命令. command 3>&2 2>&1 1>&3 | ...
:实现标准输出和错误输出的交换. command 2>&1 1>&2 | ...
:错!!!不能实现标准输出和错误输出的交换. 因shell从左到右执行命令, 当执行完2>&1后, 错误输出已经和标准输出一样的, 再执行1>&2也没有意义. "2>&1 file"和 "> file 2>&1"区别
cat food 2>&1 >file
:错误输出到终端, 标准输出被重定向到文件file. cat food >file 2>&1
:标准输出被重定向到文件file, 然后错误输出也重定向到和标准输出一样, 所以也错误输出到文件file. 注意
m<&-
来关闭输入文件描述符m, 用m>&-
来关闭输出文件描述符m. <&-
, 关闭标准输出用>&-
. copy source dest | tee.exe copyerror.txt
< File awk ''
awk -f 'BEGIN{for(i=1;i<ARGC;i++)print ARGV[i]}' ${extarr[@]}
(
有特殊含义, 匹配, 替换时必须用[(]
进行sub("\\\\", "/", txt)
gsub(/(A)|(B)|(C)/, "")
`bash awk ' BEGIN { print "'\''" print "\47", "\047" A="'\''"; print A A="\47"; print A } ' ```
例:
File="FileName"
getline < File".dat"
错误
Fdat=File".dat"; getline < Fdat
正确
程默, [linux awk数组操作详细介绍] (http://www.cnblogs.com/chengmo/archive/2010/10/08/1846190.html)
awk在存储上并不支持多维数组, awk的多维数组在本质上是一维数组.
awk提供了逻辑上模拟二维数组的访问方式. 例如, array[2,4] = 1这样的访问是允许的.
awk使用一个特殊的字符串SUBSEP(\034)作为分割字段. 在上面的例子中, 关联数组array存储的键值实际上是2\0344.
类似一维数组的成员测试, 多维数组可以使用if( (i,j) in array )
这样的语法, 但是下标必须放置在圆括号中.
类似一维数组的循环访问, 多维数组使用for( item in array )
这样的语法遍历数组. 与一维数组不同的是, 多维数组必须使用split()
函数来访问单独的下标分量. split ( item, subscr, SUBSEP)
数组为全局变量, 传值调用
<pre class="line-numbers" data-start="0"><code class="language-bash"># Language: bash echo 123 | \ awk '' function foo(fa) { fa[1]=5; print "fa[1]=" fa[1] } { a[1]=$0; print " a[1]="a[1] foo(a); print " a[1]="a[1] } '' echo "" echo 123 | \ awk '' function foo(fa,fx) { fx=fa[1]; fx=5; print "fa[1]="fa[1] ", fx="fx } { a[1]=$0; print " a[1]="a[1] foo(a); print " a[1]="a[1] }' </code></pre>printf是bash的一个命令, 也是awk中的一个函数, 作为函数的printf与C语言中的printf功能相同, 但是比起fortran的write函数, 功能还是弱了些. 比如, 多个变量的格式化输出, 利用printf要把格式写多次, 或是利用循环, 都不如write的直接使用数字简洁. 而且, printf函数使用时, 格式的数目和变量的数目必须匹配, 否则就会出错.
但bash的内置printf命令, 使用时稍有不同, 功能也更强大一些
,
分隔下面是使用示例
write(*, '(3F8.3)') a, b, c
ptintf("%8.3f %8.3f %8.3f", a, b, c)
printf "%8.3f" a b c
利用这点, 我们可以写一个函数来模拟fortran write函数.
<pre class="line-numbers" data-start="0"><code class="language-bash"># Language: bash awk '' BEGIN { a=1; b=2; c=3; FMT=fmt("4%8.3f") printf FMT"\n", a, b, c, a*b*c prt("%8.3f", a" "b" "c" "a*b*c) print"" wrt("%8.3f", a, b, c, a*b*c) } function fmt(FMT) { # 拼接格式 Nfmt=FMT gsub(/[0-9]+%/, "%", FMT) gsub(/%.*[a-zA-Z]/, "", Nfmt) for(i=1; i<=Nfmt; i++) txt=txt FMT return txt } function prt(FMT, txt) { # 任意格式输出字符串 system("printf \"" FMT "\" "txt) } function wrt(FMT, a, b, c, d, e, f, g, h, i, j, k, l, m, n) { # 多变量输出 system("printf \"" FMT "\" " \ a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n) print "" } ' </code></pre>"'"VAR"'"
)通用, 若无空格21("''"
)亦可awk '<awk expression>' "awkvar=$extvar" filename
和环境变量格式 var="this is a test"; export var; awk 'BEGIN{print ENVIRON["var"]}'
, 徒增混乱, 不建议使用'"$bshVar"'
awk '{command}'
中引用变量用单引号~/ /
可以把两个/去掉, 虽然不能用正则但可以引用awk变量测试文件BashAWK
Blank bshVar
Blank awkVar
Blank bshVar
Blank bshVar
<pre class="line-numbers" data-start="0"><code class="language-bash"># Language: bash
bshVar="Blank bshVar"
echo
echo '>>>>bshVar='$bshVar
echo '>> RegExp Method 1:'
awk ' /^'"$bshVar"'/ {print NR, $0} ' BashAwk
echo
echo '>> RegExp Method 2:'
awk ' '/^"$bshVar"/' {print NR, $0} ' BashAwk
echo
echo '>> RegExp Method 3:'
awk ' { if($0 ~ /^'"$bshVar"'/) print NR, $0 } ' BashAWK
echo
echo '>> RegExp Method 4:'
awk ' { if($0 ~ '/^"$bshVar"/') print NR, $0 } ' BashAWK
echo
echo '>> RegExp Method 5:'
awk ' { if($0 ~ "^'"$bshVar"'") print NR, $0 } ' BashAWK
echo
echo '>> RegExp Method 6:'
awk 'BEGIN{RegExp="^'"$bshVar"'"} { if($0 ~ RegExp) print NR, $0 } ' BashAWK
</code></pre>bash的heredoc在输出大段文字时很方便, perl中有类似的用法, awk中没有, 但是可以模拟一下. 下面是代码
<pre class="line-numbers" data-start="0"><code class="language-bash"># Language: bash awk ' BEGIN { Out="OutFile"; awkVar="AWK" # 直接使用bash的heredoc功能, 只用于输出到文件, 且其中的awk变量无法引用 "'$( cat >Out <<END 1 2 Out awkVar END )'" # 赋值给变量, 使用printf txt="'"$( awk '{printf "%s\\n",$0 }' <<END 1 2 awk variable: <"awkVar"> awk field: <"\$2"> END )"'" print txt # 使用print不可换行 txt="'"$( awk '{print}' <<END awk variable: <"awkVar"> awk field: <"\$2"> END )"'" print txt }' </code></pre>