在同一行 Bash 中回显多个变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31929621/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Echo multiple variables in same line Bash
提问by AS0207
I want to echo two variables on the same line.
I want to store 2015-03-04.01.Abhi_Ram.txt in a variable FILENAME and 10 in a variable COUNT and echo them simultaneously.
我想在同一行上回显两个变量。
我想将 2015-03-04.01.Abhi_Ram.txt 存储在变量 FILENAME 中,将 10 存储在变量 COUNT 中并同时回显它们。
Sample.txt
示例.txt
2015-03-04.01.Abhi_Ram.txt 10
2015-03-04.02.Abhi_Ram.txt 70
2015-03-04.01.Abhi_Ram.txt 10
2015-03-04.02.Abhi_Ram.txt 70
Below is the code I came up with:
下面是我想出的代码:
for line in `hadoop fs -cat sample.txt`
do
VAR="${line}"
FILENAME=`echo ${VAR}|awk '{print }'`
COUNT=`echo ${VAR}|awk '{print }'`
COUNT_DT=`date "+%Y-%m-%d %H:%M:%S"`
echo db"|"Abhi_Ram"|"record_count"|"${FILENAME}"||"${COUNT}"||"${COUNT_DT} >> output.txt
done
I want the output as:
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.txt||10||timestamp db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.txt||70||timestamp
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.txt||10||时间戳 db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.txt||70||时间戳
I'm getting the output as:
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.txt||||timestamp
db|Abhi_Ram|record_count|10||||timestamp
db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.txt||||timestamp
db|Abhi_Ram|record_count|70||||timestamp
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.txt||||时间戳
db|Abhi_Ram|record_count|10||||时间戳
db|Abhi_Ram|record_count|2015-03-04.02.Abhi|_Ram |时间戳
数据库|Abhi_Ram|record_count|70||||时间戳
Could someone point me what I am missing?
有人可以指出我缺少什么吗?
回答by John1024
Consider:
考虑:
while read filename count
do
count_dt=$(date "+%Y-%m-%d %H:%M:%S")
echo "db|Abhi_Ram|record_count|${filename}||${count}||${count_dt}"
done <sample.txt >>output.txt
This produces the file:
这将生成文件:
$ cat output.txt
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.json||10||2015-08-10 14:42:39
db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.json||70||2015-08-10 14:42:39
Notes:
笔记:
It is best practice to use lower or mixed case for your shell variables. The system uses upper case variables and you don't want to accidentally overwrite one.
The many double-quotes in the
echo
statement were unnecessary. The whole of the output string can be inside one double-quoted string.If you want to read a file one line at a time, it is safer to use the
while read ... done <inputfile
construct. Theread
statement also allows us to easily define thefilename
andcount
variables.For command substitution, many prefer the form
$(...)
over the backtick form. This is because (a) the$(...)
makes the beginning and end of the command substitution visually distinct, (b) the$(...)
form nests well, and (c) not all fonts clearly show backticks as different from regular ticks. (Thanks Chepner.)For efficiency, the redirection to
output.txt
has been moved to the end of the loop. In this way, the file is only opened and closed once. (Thanks Charles Duffy.)Unless you need
count_dt
updated with each individual entry, it could be placed before the loop and set just once everytimesample.txt
was processed. If you have an up-to-date version of bash (no Mac OSX), then thecount_dt
assignment can be replaced (Thanks Charles Duffy) with a native bash statement (no shelling out required):printf -v count_dt '%(%Y-%m-%d %H:%M:%S)T'
最佳做法是对 shell 变量使用小写或混合大小写。系统使用大写变量,您不希望意外覆盖一个。
echo
声明中的许多双引号是不必要的。整个输出字符串可以在一个双引号字符串中。如果您想一次读取一行文件,使用该
while read ... done <inputfile
构造更安全。该read
语句还允许我们轻松定义filename
和count
变量。对于命令替换,许多人更喜欢这种形式
$(...)
而不是反引号形式。这是因为 (a)$(...)
使命令替换的开头和结尾在视觉上不同,(b)$(...)
形式嵌套良好,以及 (c) 并非所有字体都清楚地显示反引号与常规刻度不同。(谢谢切普纳。)为了提高效率,重定向到
output.txt
已移动到循环的末尾。这样,文件只打开和关闭一次。(感谢查尔斯·达菲。)除非您需要
count_dt
对每个单独的条目进行更新,否则可以将其放置在循环之前并在每次sample.txt
处理时设置一次。如果您有最新版本的 bash(没有 Mac OSX),则count_dt
可以使用本机 bash 语句(无需脱壳)替换该分配(感谢 Charles Duffy):printf -v count_dt '%(%Y-%m-%d %H:%M:%S)T'
回答by Gordon Davisson
John1024 has explained how to do this correctly; I'd like to take a look at why the original version didn't work. The basic problem is that for
loops over words, not over lines. The file has two words on each line (a filename and a count), so it runs the loop twice per line. To see this, try:
John1024 已经解释了如何正确地做到这一点;我想看看为什么原始版本不起作用。基本问题是for
循环遍历words,而不是遍历行。该文件每行有两个词(一个文件名和一个计数),因此它每行运行两次循环。要看到这一点,请尝试:
for line in `hadoop fs -cat sample.txt`
do
echo "$line"
done
...and it'll print something like:
...它会打印如下内容:
2015-03-04.01.Abhi_Ram.txt
10
2015-03-04.02.Abhi_Ram.txt
70
...which isn't what you want at all. It also has some other unpleasant quirks, like if the input file contained the word "*", it'd insert a list of filenames in the current directory.
……这根本不是你想要的。它还有一些其他令人不快的怪癖,比如如果输入文件包含单词“*”,它会在当前目录中插入一个文件名列表。
The while read ... done <file
approach is the right way to iterate over lines in a shell script. It just happens to also be able to split each line into fields without having to mess with awk
(in this case, read filename count
does it).
该while read ... done <file
方法是在 shell 脚本中迭代行的正确方法。它恰好也能够将每一行拆分为字段而不必弄乱awk
(在这种情况下,read filename count
是这样)。