管道
管道的使用例子,在Linux shell中使用的非常多,本文只能简单的挑一下常用的,或者具有启发性的例子,记录有效性。
例子
从heredoc中获取输入,提供给交互式输入
交互式的shell直接从heredoc中获取输入,但是需要注意末尾的EOL不能多隐藏的空格等符号。
LIMIT=2
psql -h localhost -U gpadmin -d develop << EOL
\timing on
select ship_id from tb_scan limit $LIMIT;
-- 还可以有其他的操作等
select doc_sn form tu_doc_info limit $LIMIT;
EOL
由此,我可以想象,mysql等交试工具 也是可以的。
从文件获取
psql -h localhost -U gpadmin -d develop < some.sql
clickhouse的例子
## 创建表
clickhouse-mysql \
--src-host=127.0.0.1 \
--src-user=reader \
--src-password=Qwerty1# \
--table-templates-with-create-database \
--src-table=airline.ontime > create_clickhouse_table_template.sql
## 修改脚本
vim create_clickhouse_table_template.sql
## 导入建表
clickhouse-client -mn < create_clickhouse_table_template.sql
从管道中获取
cat some.sql | psql -h localhost -U gpadmin -d develop
利用提供的命令
psql -h localhost -U gpadmin -d develop -f some.sql
psql -h localhost -U gpadmin -d develop -c "select * from some table ....."
定义多行的文本
query_sql是定义的多行文本,query_sql中的换行符号,会被换成一行。坑:*会被转义为具体的文件列表。
sql中也不能有解释,因为在转换成一行的过程中,会混在一起,导致失效。
方式一,cat+heredoc 来定义多行文本
多行文本,会被转换为单行。丢失原来的换行符号。故,如果有注释,则必须要删除。
query_sql=$(cat <<EOL
SELECT
scan_site,
count(*) as cnt
FROM
(
SELECT
ship_id,
scan_site,
ROW_NUMBER () OVER (
PARTITION BY ship_id
ORDER BY
ins_db_tm DESC
) AS rn
FROM
tb_scan
WHERE
ins_db_tm >= '#START_DATE'
AND ins_db_tm < '#END_DATE'
AND scan_typ = '10'
AND rmk_id = '1'
) AS T
WHERE
T.rn = 1
GROUP BY scan_site
order by cnt desc;
EOL
)
query_sql=$(
echo "$query_sql" |
sed "s/#START_DATE/$START_DATE/g"|
sed "s/#END_DATE/$END_DATE/g" |
sed "s/#SCAN_SITE/$SCAN_SITE/g"
)
psql -h localhost -U gpadmin -d develop -e -c "$query_sql"
注意,上面也有sed的多行写法的范例。
备注:query_sql=$(cat <<EOL这种方式定义的多行文本,在echo的时候,变量需要加双引号,否则,会变成单行的文本。
- 方式二,双引号等,也能定义多行文本
SQL="
with tb as (select * from tb_scan where ins_db_tm > '${DAY_AGO_10}' and ship_id = '${SHIP_ID}' )
select * from tb_scan where ins_db_tm > '${DAY_AGO_10}' and ship_id in (select grp_ship_id from tb) union all select * from tb order by ins_db_tm;
"
echo $SQL # echo 就会将*替换调,不echo 就没事
方式三,read到变量中,等同于方式一。
多行文本,会被转换为单行。
read -d "" fcyf_some_sql << EOF select count(*) as 总数, xxx kjkdf EOF echo $fcyf_some_sql
极简方式:
懒得再定义,直接在命令行中写要执行的sql。
psql -h localhost -U gpadmin -d develop -e -c " select count(*) from tu_doc_info where dtime >= '$START_DATE' and dtime < '$END_DATE' "
# 其实clickhouse也是差不多的
clickhouse-client --query "CREATE DATABASE IF NOT EXISTS tutorial"
cat + heredoc
写入文本
比如,没有vi的时候,甚至,因为vi复制粘贴的时候,会多出换行符号,都可以使用该方式来写入到文件。
cat > target.txt <<EOL
a
bb dafadsf
EOL
# - EOL 去掉前导的空白符号等
# 'EOL' 不解析变量
cat <<EOL > target.txt
EOL
- 先处理,再写入到文件
cat <<EOL |sed 's/^/you-get -l /' > target.txt
http://url.com/1
http://url.com/1
EOL
while + read
具体参考文章。
echo 方式
通过管道,交给交互式shell中
echo "SELECT * FROM system.numbers LIMIT 10000000 OFFSET 10000000" | clickhouse-benchmark -i 10
说说echo的坑
# 正常
echo "SELECT * FROM system.numbers LIMIT 10000000 OFFSET 10000000"
# 赋值给变量
SQL="SELECT * FROM system.numbers LIMIT 10000000 OFFSET 10000000"
# 上面的 * 别解析成了具体的 文件列表。
echo $SQL
# 为了不被解析,应将上述变量,包括在括号内
echo "$SQL"
坑:echo 后面的变量,如果缺少了双引号包裹,则,变相的,拆分成了n个参数,echo * 确实会输出文件列表。
sh + heredoc
以下是综合上面的例子,使用到sh命令行上的例子。shell也是交互式的,通过,heredoc方式,让多行的代码,更容易理解一点。但是,需要注意,heredoc中的变量不要被提前解析。
- 方式一
cat <<'EOL' |sh
for var in {1..10};do
echo $var
done
EOL
- 方式二
sh <<'EOL'
for var in {1..10};do
echo $var
done
EOL
- 方式3
echo '
for var in {1..10};do
echo $var
done ' |sh
错误
原因说明:有效果,但是输出的都是空。为啥?因为$var 在EOL阶段被解析了,在传入到sh中,即为空字符串了。
sh <<EOL
for var in {1..10};do
echo $var
done
EOL
其实想多了
在shell模式下,输出以下内容,换行的时候,其实,shell能正确的识别内容还没有输入完,还接着让你输入。
for each in ./*;do
总结
管道符号 |
多个进程之间,使用该方式来传递数据。多个程序,程序之间没有缓存,如果其中一个进程卡了一会,貌似其他进程也会卡着。可以使用多次。
输出重定向符号 >
输出到文件,一般是放到最后的那条命令,唯一的例外,遇到heredoc方式,可能并不
输出重定向符号<
从文件中读取命令,放到交互试shell中,则可以使用该方式。其实跟heredoc还是挺像的。
heredoc符号 <<EOL
直接在heredoc中写文本,供交互式shell来使用。
特别说明:heredoc这种模式,必须用在命令行后面,这样shell才会识别,并且将后面的内容,作为输入的源。最好,直接跟在原始的命令行后面。
一个错误的示例如下:
因为其不是直接跟在命令行后面的。不会被识别。
MY_VAR=<<EOL
这里面的内容是不会赋值给变量,MY_VAR中的。
EOL
纠正上面的错误:
稍微注意一点的是:结束符号,EOL后面不能跟任何内容。否则,不能正常的识别。(为了满足,跟在命令行后面,刻意加的cat命令)
MY_VAR=$(cat<<EOL
这里面的内容是不会赋值给变量,MY_VAR中的。
EOL
)
如果,混合的其他的管道符号,<<EOL必须紧跟在命令行后面。
顺序问题
只遇到过heredoc+cat+管道的例子。参照前面