bash 如何遍历目录中的文件并更改路径并向文件名添加后缀
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20796200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to loop over files in directory and change path and add suffix to filename
提问by Dobrobobr
I need to write a script that starts my program with different arguments, but I'm new to Bash. I start my program with:
我需要编写一个脚本,用不同的参数启动我的程序,但我是 Bash 的新手。我开始我的程序:
./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt]
.
./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt]
.
Here is the pseudocode for what I want to do:
这是我想要做的伪代码:
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
So I'm really puzzled how to create second argument from the first one, so it looks like dataABCD_Log1.txt and start my program.
所以我真的很困惑如何从第一个参数创建第二个参数,所以它看起来像 dataABCD_Log1.txt 并启动我的程序。
回答by Gordon Davisson
A couple of notes first: when you use Data/data1.txt
as an argument, should it really be /Data/data1.txt
(with a leading slash)? Also, should the outer loop scan only for .txt files, or all files in /Data? Here's an answer, assuming /Data/data1.txt
and .txt files only:
首先要注意几点:当您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
Notes:
笔记:
/Data/*.txt
expands to the paths of the text files in /Data (includingthe /Data/ part)$( ... )
runs a shell command and inserts its output at that point in the command linebasename somepath .txt
outputs the base part of somepath, with .txt removed from the end (e.g./Data/file.txt
->file
)
/Data/*.txt
扩展到 /Data 中的文本文件的路径(包括/Data/ 部分)$( ... )
运行一个 shell 命令并在命令行中的那个点插入它的输出basename somepath .txt
输出 somepath 的基本部分,从末尾删除 .txt (例如/Data/file.txt
->file
)
If you needed to run MyProgram with Data/file.txt
instead of /Data/file.txt
, use "${filename#/}"
to remove the leading slash. On the other hand, if it's really Data
not /Data
you want to scan, just use for filename in Data/*.txt
.
如果您需要使用Data/file.txt
而不是运行 MyProgram /Data/file.txt
,请使用"${filename#/}"
删除前导斜杠。在另一方面,如果它真的Data
不是/Data
要扫描,只需使用for filename in Data/*.txt
。
回答by Cong Ma
Sorry for necromancing the thread, but whenever you iterate over files by globbing, it's good practice to avoid the corner case where the glob does not match (which makes the loop variable expand to the (un-matching) glob pattern string itself).
抱歉让线程死机,但是每当您通过通配符迭代文件时,最好避免通配符不匹配的极端情况(这会使循环变量扩展为(不匹配的)通配符模式字符串本身)。
For example:
例如:
for filename in Data/*.txt; do
[ -e "$filename" ] || continue
# ... rest of the loop body
done
Reference: Bash Pitfalls
参考:Bash 陷阱
回答by Jonathan Leffler
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
The name=${file##*/}
substitution (shell parameter expansion) removes the leading pathname up to the last /
.
的name=${file##*/}
取代(壳参数扩展)删除前导路径名直到最后/
。
The base=${name%.txt}
substitution removes the trailing .txt
. It's a bit trickier if the extensions can vary.
所述base=${name%.txt}
取代去除拖尾.txt
。如果扩展名可以变化,那就有点棘手了。
回答by James
You can use finds null separated output option with read to iterate over directory structures safely.
您可以将 finds 空分隔输出选项与 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 $'[/home/$] for filename in /Data/*.txt; do for i in {0..3}; do ./MyProgam.exe Data/filenameLogs/$filename_log$i.txt; done done
' 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
So for your case
所以对于你的情况
#!/bin/bash
for filename in /Data/*.txt;
do
for i in {0..3};
do ./MyProgam.exe Data/filename.txt Logs/$filename_log$i.txt;
done
done
additionally
此外
##代码##will run the while loop in the current scope of the script ( process ) and allow the output of find to be used in setting variables if needed
将在脚本( process )的当前范围内运行 while 循环,并允许 find 的输出在需要时用于设置变量
回答by user3183111
Looks like you're trying to execute a windows file (.exe) Surely you ought to be using powershell. Anyway on a Linux bash shell a simple one-liner will suffice.
看起来您正在尝试执行 Windows 文件 (.exe) 您当然应该使用 powershell。无论如何,在 Linux bash shell 上,一个简单的单行就足够了。
##代码##Or in a bash
或者在 bash 中
##代码##