[root@test200 ~]# cat test
a
b
c
d
e
f
[root@test200 ~]# sed ‘/c/{p;:a;N;$!ba;d}’ test
a
b
c
定义一个标签a,匹配c,然后N把下一行加到模式空间里,匹配最后一行时,才退出标签循环,然后命令d,把这个模式空间里的内容全部清除。
if 匹配”c”
:a
追加下一行
if 不匹配”$”
goto a
最后退出循环,d命令删除。
[root@test200 ~]# cat test
a
b
c
d
e
f
[root@test200 ~]# sed ‘/c/{p;:a;N;$!ba;d}’ test
a
b
c
定义一个标签a,匹配c,然后N把下一行加到模式空间里,匹配最后一行时,才退出标签循环,然后命令d,把这个模式空间里的内容全部清除。
if 匹配”c”
:a
追加下一行
if 不匹配”$”
goto a
最后退出循环,d命令删除。
以下是我在编程时的亲身体会:
先看如下的程序:
#!/bin/sh
count=0
while read LINE
do
count=`expr $count + 1`
done < file
echo $count
问题是这个程序能得到什么样的结果?仿佛很明显,能够统计文件file的行数,然而你若执行一下便知,无论file的行数是多少,该程序的输出始终是0!为什么?
原来如果使用for,while,until,if,case这些命令时用到了重定向,那么sh会产生一个子shell来运行它们。可以想象count在循环体中能够正确的计数,一旦while执行完毕,子shell完成,其内部的变量count就消失了。因而得到的结果是循环体外开始赋的值0!
可以避免吗?试试这样:
cat file|while read LINE
do
count=`expr $count + 1`
done
echo $count
依然如此!怎么办?可以先关闭标准输入,然后以你要读取得文件重新打开它,这样就不需要对while命令的输入进行改向,也就不会用子shell的方式来运行它了。如下:
exec<file
count=0
while read LINE
do
count=`expr $count + 1`
done
exec < /dev/tty
echo $count
也可以
exec 4<&0 0< file
count=0
while read LINE
do
count=`expr $count + 1`
done
exec 0<&4
echo $count
如果还有怀疑的话可以试一下if:
#!/bin/sh
echo "abcd"|if [ "abcd" = "abcd" ]; then
var=7
fi
echo $var
输出当然是空。去掉echo "abcd"|就好了。
所以不了解这一点在编程时就会非常危险,试想while,for,case,if,until是多么的常用,与管道或重定向连着用也是很常见的,可是一旦在其内部使用了什么变量,就是有进无出,有去无回了。
以上的说法仅限于sh编程,对于ksh,bash,据我所知都不会有这个问题,它们处理的时候不会当作子shell来做。其它种类的shell可以自己试一试。
http://hi.baidu.com/test/blog/item/16ecf01f6f46e4f7e0fe0b10.html
当while read 遇上ssh
2007-08-15 21:13先看一段简化过的BASH SHELL代码
TODAY=`date +%Y%m%d`
SUFFIX=”tar”
CONF=the_config_file
i=0
while read HOST SRCPATH DSTPATH
do
(( i++ ))
if [ “X${HOST:0:1}” = “X#” -o ${#DSTPATH} -eq 0 ]
then
#忽略注释行及少于3个项的记录
else
ssh ${HOST} “tar c ${SRCPATH}” >${DSTPATH}.${TODAY}.${SUFFIX} 2>/dev/null
fi
done < $CONF
作者的本意是通过脚本读取配置文件$CONF,然后打包备份$CONF中指定的文件,但执行后发现程序在成功备份$CONF中指定的第一个文件后即退出……
跟踪后发现read在备份完第一个文件后就再读不到任何数据,所以while循环结束--也就是说,
通过重定向$CONF文件传给标准输入的数据被
ssh ${HOST} “tar c ${SRCPATH}” >${DSTPATH}.${TODAY}.${SUFFIX} 2>/dev/null
这个命令提前吃掉了。
将其改为
ssh ${HOST} “tar c ${SRCPATH}” >${DSTPATH}.${TODAY}.${SUFFIX} 2>/dev/null </dev/null
将ssh的标准输入重定向到/dev/null,程序正常备份所有$CONF中指定的文件。
while read line的一些问题
Q1. 曾经面试的时候被问到一个问题, 说
while read line ; do
echo $line ;
done < ./a.txt
失败, 会是什么原因, 当时觉得不太可能, 就回答了“我用的时候没有碰到过这种情况”。 前段在写一个脚本的时候, 确实遇到了所谓的while read 失败, 原因是我读入的文件是在win下用dos格式保存的文本, 所以每行结束都带有一个\r字符, 这个字符在linux/unix环境下的作用是“回到一行的开始”, 如果再对$line做相关的字符串操作的话(比如字符串连接), 得到的结果可能会让人迷惑… 所以当把win下编译的文本用在linux/unix环境时, 最好做一下格式转换
Q2. 2009-08-01更新:
# cat ur_file
1234 abcd
5678 efgh
# vi t3.sh
#!/bin/bash
while read t1 t2 ; do
echo $t1 $t2 ; awk ‘{ print $0 }’
done < ./ur_file
#./t3.sh
1234 abcd
5678 efgh
# sh -x ./t3.sh 发现只read 了一次
Q3.
# seq 10 > file
# while read line ; do
> echo $line
> dd &>/dev/null
> done < ./file
1
为什么这里只打印第一行呢?
问题的关键在于:
read从输入读取了一行内容后,
其它的程序(比如 rsh或sed)从同样的地方把其它的输入读走了,
read当然读不到其它内容了,
while也就结束了
摘自:http://bbs.chinaunix.net/viewthread.php?tid=769040&extra=&page=2
可以打开set -x, 看看, 确实只read了两次, 第一次read出第一行, 第二次read不到就退出while循环
read 和 dd都从文件描述符3中读取数据
The default maximum allowed packget size is 1MB, so if you store some large binaries in your database you might get some problems. All you need to do is re-set the maximum size to a larger number.
Macintosh:trunk jennyfong$ mysql -uroot database_name < database_backup.sql
ERROR 1153 (08S01) at line 2365: Got a packet bigger than ‘max_allowed_packet’ bytes
Macintosh:trunk jennyfong$ mysql -uroot
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 25
Server version: 5.0.86 MySQL Community Server (GPL)
Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.
mysql> set global net_buffer_length=10000000;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> set global max_allowed_packet=1000000000;
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
Macintosh:trunk jennyfong$ mysql -uroot database_name < database_backup.sql
show variables like ‘max_allowed_packet’;