bash 从文件中执行读取命令

Teb*_*ebe 1 shell bash quoting

经过一些操作后,我得到了包含命令的文件,我很高兴能够执行这些命令。

输入文件(文件名为 inp2.txt):

"02 - Beautiful Emptiness.mp3"
"02 - Come. mp3"
"02 - Go For It.mp3"
Run Code Online (Sandbox Code Playgroud)

代码:

#!/bin/bash
exec 4<inp2.txt           # opening  file via descriptor
while read LINE <&4; do
    printf "%s\n" "$LINE"  # just to watch that command is proper
    $LINE                # execute command
done
Run Code Online (Sandbox Code Playgroud)

编辑:抱歉,我省略了我认为对理解不重要的重要代码部分。完整代码:

#!/bin/bash
IFS='
 '
declare LINE
declare BUF
declare a
a=1 

rm inp2.txt # delete previous version of file
exec 3< inp.txt # open descriptor for a file()content of it is written above
while read LINE <&3; do  # read it
    printf "mv ""$LINE"" %s\n" """$a"".mp3" >> inp2.txt 
    # form a command and output it to the file, just to make sure that I got a command that I really want
    let "a++"  # increment number that will be a part of new unique name
done

exec 4<inp2.txt #open again descriptor with ready commands

while read LINE <&4; do
    printf "%s\n" "$LINE"  # check again
    $LINE #  here it should be executed, but I get mistakes that  is pointed down
done

exit 0
Run Code Online (Sandbox Code Playgroud)

输出:

在此处输入图片说明

似乎命令是正确的,但是出了点问题,我无法弄清楚到底出了什么问题。

Gil*_*il' 8

您发布的脚本、数据文件和输出不一致。脚本和数据文件都不包含mv,但您的屏幕截图包含。此外,您的屏幕截图提到了您发布的脚本没有的第 28 行。当您向我们提供不一致的信息时,很难查明您的问题。

也就是说,您正在尝试做两件事情中的一件,而这两件事情都不能像您尝试的那样工作。

  • 如果输入文件包含类似的行

    mv "02 - Beautiful Emptiness.mp3" 1.mp3
    
    Run Code Online (Sandbox Code Playgroud)

    那么它实际上是一个shell脚本。与其逐行读取,不如将其作为 shell 脚本执行。确保您可以信任此文件,因为您将执行其中的任何内容,包括rm -rf ~或其他一些内容。

    . inp2.sh
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果输入文件包含类似的行

    mv "02 - Beautiful Emptiness.mp3" 1.mp3
    
    Run Code Online (Sandbox Code Playgroud)

    那么你阅读它的方式就行不通了。read LINE执行以下操作:

    • 读一行;
    • 如果该行以反斜杠结尾,则删除反斜杠并读取另一行(重复直到读取了不以 a 结尾的行\);
    • 仅用第二个字符替换所有反斜杠+字符序列;
    • 设置LINE为读取的行的串联,减去换行符。

    当 shell 执行命令时$LINE,它会做它在看到引号外的变量替换时总是做的事情,即:

    • 将变量的值拆分为包含空格的每个位置的单词列表(假设默认值为IFS);
    • 将每个单词视为一个 glob 模式,如果它至少匹配一个文件,则将其展开。

    听起来没用?这是。请注意,这里没有关于引号的内容:引号是 shell 语法的一部分,它们不是 shell 扩展规则的一部分。

您可能应该inp2.txt包含一个文件名列表,每行一个。请参阅为什么经常使用 `while IFS= read`,而不是 `IFS=; 阅读时..`?了解如何从文件中读取行列表。你会想要类似的东西

i=1
while IFS= read -r source; do
  dir=$(dirname -- "$source")
  ext=
  case "${source##*/}" in
    *.*) ext=.${source##*.};;
  esac
  mv -- "$source" "$dir/$i$ext"
done <inp2.txt
Run Code Online (Sandbox Code Playgroud)

为了完整起见,我会提到另一种可能性,但我不推荐它,因为它很繁琐,而且它不会让你做你似乎在做的事情。像这样的文件

. inp2.sh
Run Code Online (Sandbox Code Playgroud)

然后它可以被xargs命令读取。输入到xargs以空格分隔的元素列表,它可以是由单引号包围的文字(可能包含空格)、由双引号包围的文字(可能包含空格)或可能包含反斜杠转义的未加引号的文字(\引用下一个字符)。请注意,该xargs语法与 shell 可能识别的任何内容都不同。