在同一行 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:03:30  来源:igfitidea点击:

Echo multiple variables in same line Bash

bashecho

提问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:

笔记:

  1. 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.

  2. The many double-quotes in the echostatement were unnecessary. The whole of the output string can be inside one double-quoted string.

  3. If you want to read a file one line at a time, it is safer to use the while read ... done <inputfileconstruct. The readstatement also allows us to easily define the filenameand countvariables.

  4. 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.)

  5. For efficiency, the redirection to output.txthas been moved to the end of the loop. In this way, the file is only opened and closed once. (Thanks Charles Duffy.)

  6. Unless you need count_dtupdated with each individual entry, it could be placed before the loop and set just once everytime sample.txtwas processed. If you have an up-to-date version of bash (no Mac OSX), then the count_dtassignment 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'
    
  1. 最佳做法是对 shell 变量使用小写或混合大小写。系统使用大写变量,您不希望意外覆盖一个。

  2. echo声明中的许多双引号是不必要的。整个输出字符串可以在一个双引号字符串中。

  3. 如果您想一次读取一行文件,使用该while read ... done <inputfile构造更安全。该read语句还允许我们轻松定义filenamecount变量。

  4. 对于命令替换,许多人更喜欢这种形式$(...)而不是反引号形式。这是因为 (a)$(...)使命令替换的开头和结尾在视觉上不同,(b)$(...)形式嵌套良好,以及 (c) 并非所有字体都清楚地显示反引号与常规刻度不同。(谢谢切普纳。)

  5. 为了提高效率,重定向到output.txt已移动到循环的末尾。这样,文件只打开和关闭一次。(感谢查尔斯·达菲。)

  6. 除非您需要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 forloops 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 <fileapproach 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 countdoes it).

while read ... done <file方法是在 shell 脚本中迭代行的正确方法。它恰好也能够将每一行拆分为字段而不必弄乱awk(在这种情况下,read filename count是这样)。