Bash:将两个变量用冒号连接在一起会导致行为不可预测。

huangapple go评论48阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年7月28日 03:16:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76782791.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定