在Bash中执行带有变量的命令并存储结果

9

我不知道如何使用变量执行命令并获取其结果。我有许多.h.c文件,需要将每个文件从ISO-8859转换为UTF-8。

所以我执行以下操作:

ls | grep "\.[ch]" | xargs myscript.sh

在我的脚本中,文件名存储在变量$1中。现在我需要执行以下操作:
iconv -f ISO-8859 -t UTF-8 $1

并且存储此结果,因为 iconv 会打印到标准输出。

result=`iconv -f ISO-8859 -t UTF-8 $1`

echo $result

这似乎不起作用,因为它给了我一些不匹配的东西,而不是转换后的$1


3
「不匹配?」请引用您收到的精确错误信息。 - hmakholm left over Monica
1
这不是错误。这是多个文件的混合内容,不仅仅是$1,我不理解它。 - designerrr
你用 ls | grep .. 命令列出的文件中,有没有文件名中带空格的?那会导致问题。尝试将 result=... 中的 $1 改为 "$1",但你可能需要想办法处理文件名中的空格。请编辑你的问题,提供适当的 $1 示例值和 scramble 内容的确切文本。祝好运。 - shellter
如果您的文件足够小,可以使用带有双引号的 echo "$result" 以保留内部间距。如果没有双引号,则输出为单行,并将一个或多个空格序列缩减为单个空格。 - Jonathan Leffler
规范的问题是 如何在Bash中将变量设置为命令输出?。尽管标题不太具体,但它涵盖了将(变量)输入到外部命令**(在(Bash)变量中)的情况。 - Peter Mortensen
3个回答

8
如果您需要在数据上进行某种转换,可以使用以下语法“捕获”输出:
result="$(iconv -f ISO-8859 -t UTF-8 $1)"

这里还有一个需要注意的问题:如果你要存储大量可能包含空格或其他干扰字符的数据,请确保始终引用变量(使用"$result"而不是$result),以确保它被视为单个字符串。


这个 $cmd $1 > $1 不仅会覆盖文件,而且会先清空它。这是截断所有源文件的好方法。 - sehe
又修好了。天哪,我的 shell 真是生疏了。 - Michael
好的,-1已移除 :) 附言:这些可能是C语言源文件,所以除非它是混淆代码竞赛的提交,否则里面肯定会有一些空格 :) - sehe
谢谢你,这给了我一些不匹配的问题,因为我在回显时没有引用 $result。 - designerrr

3

这里有一个解决方案,甚至可以处理换行符:

find -name '*.[ch]' \
    -exec mv '{}' '{}.backup' \; \
    -exec iconv -f ISO-8859 -t UTF-8 '{}.backup' -o '{}' \;

通常情况下,如果你要使用结果,则永远不要解析文件名。我知道的唯一合理的方式是:
  1. 使用 shell 通配符,例如for file in ./*.[ch] ; do echo "$file" ; done。只适用于一个目录。
  2. 结合使用find-exec
  3. 结合使用 'find' 和 -print0 (以 \0 分隔字符串打印文件名),并使用输出来构建命令行与 xargs -0 并可能还需要助手脚本。但这非常麻烦。
此外,请确保您使用的相对文件名以./为前缀。调用mv -from -to不安全,但mv ./-from ./-to是安全的,并且会执行所需操作。例如,在使用通配符时,使用./*.c而不是*.c

3
我会这样做:
while read filename; 
do
    mv "$filename" "$filename.bck" && \
        iconv -f ISO-8859 -t UTF-8 "$filename.bck" > "$filename"
done < find -iname '*.[hc]'

这将在运行时创建备份,并且还处理带有空格的文件(而不是换行符)。


双引号可以处理字符串(文件名)中的换行符。 - Jonathan Leffler
1
@JonathanLeffler:我认为sehe在谈论换行符时指的是while read。如果我没记错,在bash中你可以这样做while read -d $'\x00' - ninjalj
好的 - 是的; while read filename 无法处理换行符。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接