我需要编写一个脚本以不同的参数启动程序,但是我是Bash的新手。我用以下代码启动程序:

./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt]

这是我要执行的操作的伪代码:

for each filename in /Data do
  for int i = 0, i = 3, i++
    ./MyProgram.exe Data/filename.txt Logs/filename_Log{i}.txt
  end for
end for


所以我真的很困惑如何从第一个参数创建第二个参数,因此看起来像dataABCD_Log1.txt并启动我的程序。

#1 楼

首先要注意以下几点:当使用Data/data1.txt作为参数时,它真的应该是/Data/data1.txt(带斜杠)吗?另外,外循环应仅扫描.txt文件还是/ Data中的所有文件?这是一个答案,假设仅/Data/data1.txt和.txt文件:

#!/bin/bash
for filename in /Data/*.txt; do
    for ((i=0; i<=3; i++)); do
        ./MyProgram.exe "$filename" "Logs/$(basename "$filename" .txt)_Log$i.txt"
    done
done


注意: / Data(包括/ Data /部分)中文本文件的路径

/Data/*.txt运行shell命令,并将其输出插入命令行中的该点

输出somepath的基部,并从结尾删除.txt(例如,$( ... )-> basename somepath .txt

如果需要使用/Data/file.txt而不是file运行MyProgram,请使用Data/file.txt删除前导斜杠。另一方面,如果要扫描的确实是/Data/file.txt而不是"${filename#/}",请使用Data

评论


显然,基名-s是非标准扩展名-我将编辑答案以使用标准语法。

–戈登·戴维森(Gordon Davisson)
13年12月27日在16:23

如果未找到/匹配任何文件,则我发现for循环执行块的通配符仍然使用filename =“ /Data/*.txt”输入一次。如何避免这种情况?

–奥利弗·皮尔曼(Oliver Pearmain)
2015年2月3日,15:22

@OliverPearmain可以在循环之前使用shopt -s nullglob(在以后使用shopt -u nullglob以避免以后出现问题),或者添加[[! -e“ $ filename]];然后继续;在循环开始时执行fi,因此它将跳过不存在的文件。

–戈登·戴维森(Gordon Davisson)
15年2月3日,19:01

当某些文件名称中包含空格时,这将不起作用。

–伊莎·哈森(Isa Hassen)
16年1月24日在20:29

@Isa只要所有的双引号都到位,它就应该与空白一起使用。忽略任何双引号,您将遇到空格问题。

–戈登·戴维森(Gordon Davisson)
16年1月25日,0:01

#2 楼

很抱歉,该线程无法正常使用,但是每当您通过遍历遍历文件时,都应避免在这种情况下避免遍历不匹配的情况(这会使循环变量扩展为(不匹配的)遍历模式字符串本身)。 br />
例如:

for filename in Data/*.txt; do
    [ -e "$filename" ] || continue
    # ... rest of the loop body
done


参考:重击陷阱

评论


这仍然是及时的警告。我以为自己创建的脚本不正确,但是我的文件扩展名是小写而不是大写,没有找到文件,并返回了glob模式。啊。

– RufusVS
17年9月14日在21:13

由于使用了Bash标记:这就是shopt nullglob的目的! (或也可以使用shopt failglob,具体取决于您想要的行为)。

– gniourf_gniourf
17年12月18日在17:46



此外,这还在循环到达之前检查在处理期间删除的文件。

–loxaxs
18年1月1日在22:26

还可以处理您拥有名为dir.txt的目录的情况

– vidstige
18年5月3日在23:41

#3 楼

for file in Data/*.txt
do
    for ((i = 0; i < 3; i++))
    do
        name=${file##*/}
        base=${name%.txt}
        ./MyProgram.exe "$file" Logs/"${base}_Log$i.txt"
    done
done


name=${file##*/}替换(shell参数扩展)将删除最后一个/的前导路径名。如果扩展名可以变化,这会有些棘手。

评论


我相信您的代码中有错误。一行应该是base = $ {name%.txt},而不是base = $ {base%.txt}。

–caseklim
14年5月15日在1:16

@CaseyKlimkowsky:是的;当代码和注释不一致时,至少其中之一是错误的。在这种情况下,我认为它只是一个代码。通常,实际上两者都是错误的。感谢您指出了这一点;我已经解决了。

–乔纳森·莱弗勒(Jonathan Leffler)
14年5月15日在1:21

除了使用name = $ {file ## * /}之外,您还可以使用name =`basename $ file`

– Tk421
10月18日23:08

#4 楼

您可以将finds null分隔的输出选项与read一起使用,以安全地遍历目录结构。

#!/bin/bash
find . -type f -print0 | while IFS= read -r -d $'
#!/bin/bash
find . -maxdepth 1 -type f  -print0 | while IFS= read -r -d $'
#!/bin/bash
while IFS= read -r -d $'q4312078q' file; do
  for ((i=0; i<=3; i++)); do
    ./MyProgram.exe "$file" 'Logs/'"`basename "$file"`""$i"'.txt'
  done
done < <(find . -maxdepth 1 -type f  -print0)
' file; do for ((i=0; i<=3; i++)); do ./MyProgram.exe "$file" 'Logs/'"`basename "$file"`""$i"'.txt' done done
' file; do echo "$file" ; done


因此,对于您而言
>



q4312078q

将在脚本的当前作用域(进程)中运行while循环,并允许将find的输出用于设置变量如果需要

评论


$'\ 0'是一种怪异的书写方式“”。您缺少IFS =,并且-r切换为read:您的read语句应为:IFS = read -rd”文件。

– gniourf_gniourf
19年2月8日在11:31

我认为有些需要搜索$'\ 0'并在其中散布一些堆栈点。进行您指出的编辑。没有IFS =尝试echo -e“ ok \ nok \ 0”的不良影响是什么?同时读取-d''行;做echo -e“ $ line”;完成似乎没有任何。另外,我看到的-r通常是默认设置,但是找不到防止它发生的示例。

–詹姆斯
19年2月9日在22:56

如果文件名以空格结尾,则需要IFS =:请尝试触摸“ Prospero”(注意尾随空格)。另外,如果文件名带有反斜杠,则需要使用-r开关:触摸“ Prospero \ n”来尝试使用它。

– gniourf_gniourf
19年2月9日在23:02



被低估的答案。在包含超过100k文件的目录中尝试获得最高支持的文件。如果您使用的是低端计算机,请祝您好运。

–五彩纸屑
6月14日8:10

#5 楼

看起来您正在尝试执行Windows文件(.exe),当然应该使用powershell。无论如何,在Linux bash shell上,一个简单的单行代码就足够了。

在bash中或者在bash中