英文:
Bash: concatenate two variables with colon in the middle results in unpredictable behaviour
问题
以下是您要翻译的内容:
我有一个包含以日期开头的文件的目录。
for file in ./my_dir/*; do
first_line=$(head -n 1 "$file")
echo $file:$first_line
done
这会按预期打印如下:
> ./my_dir/file.md:23/07/2023
当我将$file
和$first_line
的顺序切换如下:
for file in ./my_dir/*; do
first_line=$(head -n 1 "$file")
echo $first_line:$file
done
输出变成了:
> :./my_dir/file.md
$first_line
完全被忽略了。我的期望是它应该是这样的:
> 23/07/2023:./my_dir/file.md
我尝试过更改分隔符和文件的第一行。使用${first_line}:${file}
,"${first_line}:${file}"
也没有起作用。
英文:
I have a directory containing files that start with a date.
for file in ./my_dir/*; do
first_line=$(head -n 1 "$file")
echo $file:$first_line
done
This prints as below, which is expected:
> ./my_dir/file.md:23/07/2023
When I switch the order of the $file
and $first_line
like this:
for file in ./my_dir/*; do
first_line=$(head -n 1 "$file")
echo $first_line:$file
done
The output becomes:
> :./my_dir/file.md
The $first_line
is completely ignored. My expectation was it to be like this:
> 23/07/2023:./my_dir/file.md
I've tried changing the delimiter and the first line of the files. Using ${first_line}:${file}
, "${first_line}:${file}"
didn't work too.
答案1
得分: 1
我已经在macOS和Ubuntu 22.04上尝试了您的解决方案,并获得了以下结果:
head: error reading './my_dir': Is a directory
这是因为for file in ./my_dir
只返回./my_dir
。它不返回该目录中的文件列表。
我发现以下方法有效。请注意通配符:
for file in ./my_dir/*
do
first_line=$(head -n 1 "$file")
echo "$first_line:$file"
done
更新
如果您不介意使用awk,以下方法也有效:
awk 'FNR==1 {print $0 ":" FILENAME}' ./my_dir/*
FNR == 1
表达式表示如果行是文件中的第一行。
更新 2
这是一个awk命令,它去掉了末尾的CRLF,应该能解决您的问题:
awk 'FNR==1 {sub(/[\r\n]*$/, ""); print $0 ":" FILENAME}' ./my_dir/*
更新 3
这是如何在bash中执行的方法:使用tr
命令去除CRLF:
for file in ./my_dir/*
do
first_line=$(head -n 1 "$file"| tr -d "\r\n")
echo "$first_line:$file"
done
英文:
I have tried your solution on both macOS and Ubuntu 22.04 and got:
head: error reading './my_dir': Is a directory
That is because for file in ./my_dir
only return ./my_dir
. It does not return a list of files in that directory.
I found the following works. Notice the wildcard:
for file in ./my_dir/*
do
first_line=$(head -n 1 "$file")
echo "$first_line:$file"
done
Update
If you don't mind using awk, the following also works:
awk 'FNR==1 {print $0 ":" FILENAME}' ./my_dir/*
The FNR == 1
expression says if the line is the first line in a file.
Update 2
Here is an awk command which strips the trailing CRLF, which should fix your problem:
awk 'FNR==1 {sub(/[\r\n]*$/, ""); print $0 ":" FILENAME}' ./my_dir/*
Update 3
Here is how to do it in bash: Use the tr
command to strip the CRLF:
for file in ./my_dir/*
do
first_line=$(head -n 1 "$file"| tr -d "\r\n")
echo "$first_line:$file"
done
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论