linux shell 怎么打开文件夹,关于bash:如何进入每个目录并执行命令?

我如何编写一个bash脚本,它遍历parent_directory内部的每个目录并在每个目录中执行命令。

目录结构如下:

parent_directory (name could be anything - doesnt follow a pattern)

001 (directory names follow this pattern)

0001.txt (filenames follow this pattern)

0002.txt

0003.txt

002

0001.txt

0002.txt

0003.txt

0004.txt

003

0001.txt

the number of directories is unknown.

托德(Todd)发布的答案对我有帮助。

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c"cd '{}' && pwd" \;

\( ! -name . \)避免在当前目录中执行命令。

并且,如果您只想在某些文件夹中运行命令,则:find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c"cd {} && pwd" \;

我必须做-exec bash -c cd"$0" && pwd {} \;,因为某些目录包含单引号和一些双引号。

您还可以通过添加-mindepth 1来省略当前目录

如何将其更改为接受" git remote get-url origin"之类的命令而不直接使用pwd的函数?

disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c cd"{}" &&"$@" \;}不起作用。

当前目录为parent_directory时,可以执行以下操作:

for d in [0-9][0-9][0-9]

do

( cd"$d" && your-command-here )

done

(和)创建一个子外壳,因此在主脚本中不会更改当前目录。

这里没有关系,因为通配符不匹配数字以外的任何内容,但是在一般情况下,您基本上总是希望将目录名放在循环内的双引号中。 cd"$d"会更好,因为它可以转移到通配符确实匹配名称包含空格和/或shell元字符的文件的情况。

(这里的所有答案似乎都具有相同的缺陷,但这在投票最多的答案中最重要。)

另外,绝大多数命令实际上并不关心您在哪个目录中执行它们。 for f in foo bar; do cat"$f"*.txt; done >output在功能上等效于cat foo*.txt bar*.txt >output。但是,ls是一个命令,根据传递参数的方式,它产生的输出会稍有不同。类似地,如果从子目录运行它,则输出相对文件名的grep或wc也将有所不同(但通常由于这个原因,您要避免进入精确的子目录)。

如果您使用的是GNU find,则可以尝试-execdir参数,例如:

find . -type d -execdir realpath"{}" ';'

或(根据@gniourf_gniourf注释):

find . -type d -execdir sh -c 'printf"%s/%s

""$PWD""$0"' {} \;

注意:可以使用${0#./}代替$0来固定./在前面。

或更实际的例子:

find . -name .git -type d -execdir git pull -v ';'

如果要包括当前目录,使用-exec甚至更简单:

find . -type d -exec sh -c 'cd -P --"{}" && pwd -P' \;

或使用xargs:

find . -type d -print0 | xargs -0 -L1 sh -c 'cd"$0" && pwd && echo Do stuff'

或@gniourf_gniourf建议的类似示例:

find . -type d -print0 | while IFS= read -r -d '' file; do

# ...

done

上面的示例支持名称中带有空格的目录。

或通过分配到bash数组中:

dirs=($(find . -type d))

for dir in"${dirs[@]}"; do

cd"$dir"

echo $PWD

done

将.更改为您的特定文件夹名称。如果不需要递归运行,则可以使用:dirs=(*)。上面的示例不支持名称中带有空格的目录。

因此,正如@gniourf_gniourf建议的那样,在不使用显式循环的情况下将find输出放置到数组中的唯一正确方法将在Bash 4.4中提供:

mapfile -t -d '' dirs <

还是不推荐使用的方法(涉及解析ls):

ls -d */ | awk '{print $NF}' | xargs -n1 sh -c 'cd $0 && pwd && echo Do stuff'

上面的示例将忽略当前目录(按OP的要求),但是它将破坏带有空格的名称。

也可以看看:

Bash:针对SO中的每个目录

如何在当前路径中输入每个目录并执行脚本?在SE Ubuntu

在不使用显式循环的情况下将find的输出放入数组中的唯一正确方法将在带有mapfile -t -d dirs < 的Bash 4.4中提供。在此之前,您唯一的选择是使用循环(或将操作推迟到find)。

实际上,您实际上并不需要dirs数组;您可以像这样安全地循环find的输出:find . -type d -print0 | while IFS= read -r -d file; do ...; done。

@gniourf_gniourf我是视觉的,总是尝试查找/使看起来简单的东西。例如。我已经编写了这个脚本,使用bash数组对我来说很容易理解(通过将逻辑分成较小的部分,而不是使用管道)。引入其他管道IFS,read,给人留下了额外的复杂性。我不得不考虑一下,也许有一些更简单的方法可以做到。

如果您更容易理解是破碎,那么是的,有更简单的方法。现在不用担心,随着您习惯它们,所有这些IFS和read(正如您所说的)都变成了第二自然……它们是编写脚本的规范和惯用方式的一部分。

顺便说一句,您的第一个命令find . -type d -execdir echo $(pwd){} ;并没有完成您想要的操作($(pwd)甚至在find执行之前就已展开)…

@gniourf_gniourf当Ive在扩展pwd之前尝试运行pwd时,尽管find返回不同的目录,它也无法按预期方式运行(它只显示相同的目录)。

如果顶层文件夹是已知的,则可以这样写:

for dir in `ls $YOUR_TOP_LEVEL_FOLDER`;

do

for subdir in `ls $YOUR_TOP_LEVEL_FOLDER/$dir`;

do

$(PLAY AS MUCH AS YOU WANT);

done

done

在$上(尽可能多地玩);您可以根据需要放置尽可能多的代码。

请注意,我没有在任何目录上" cd"。

干杯,

这里有几个" ls的无用使用"的实例-您可以改为for dir in $YOUR_TOP_LEVEL_FOLDER*。

好吧,也许它在一般意义上是无用的,但是它允许直接在ls中进行过滤(即,所有以.tmp结尾的目录)。那就是为什么我使用ls $dir表达式

您可以通过管道传输然后使用xargs来实现。要注意的是,您需要使用-I标志,该标志将bash命令中的子字符串替换为每个xargs传递的子字符串。

ls -d */ | xargs -I {} bash -c"cd '{}' && pwd"

您可能想用要在每个目录中执行的任何命令替换pwd。

我不知道为什么还没有提出这个建议,但是我找到了迄今为??止最简单的脚本。谢谢

别客气 !

for dir in PARENT/*

do

test -d"$dir" || continue

# Do something with $dir...

done

+1表示测试-d。帮助过我。

这很容易理解!

虽然一个内衬适合快速和肮脏的用法,但我更喜欢下面更详细的版本来编写脚本。这是我使用的模板,可以处理许多极端情况,并允许您编写更复杂的代码以在文件夹上执行。您可以在函数dir_command中编写bash代码。下面,dir_coomand以示例方式在git中实现标记每个存储库的功能。脚本的其余部分为目录中的每个文件夹调用dir_command。还包括仅遍历给定的一组文件夹的示例。

#!/bin/bash

#Use set -x if you want to echo each command while getting executed

#set -x

#Save current directory so we can restore it later

cur=$PWD

#Save command line arguments so functions can access it

args=("$@")

#Put your code in this function

#To access command line arguments use syntax ${args[1]} etc

function dir_command {

#This example command implements doing git status for folder

cd $1

echo"$(tput setaf 2)$1$(tput sgr 0)"

git tag -a ${args[0]} -m"${args[1]}"

git push --tags

cd ..

}

#This loop will go to each immediate child and execute dir_command

find . -maxdepth 1 -type d \( ! -name . \) | while read dir; do

dir_command"$dir/"

done

#This example loop only loops through give set of folders

declare -a dirs=("dir1""dir2""dir3")

for dir in"${dirs[@]}"; do

dir_command"$dir/"

done

#Restore the folder

cd"$cur"

您可以使用

find .

搜索当前目录中的所有文件/目录

比您可以像这样通过管道传递xargs命令的输出

find . | xargs 'command here'

这不是要问的。

我不了解文件的格式,因为您只想遍历文件夹...您是否正在寻找类似的东西?

cd parent

find . -type d |while read d; do

ls $d/

done

for p in [0-9][0-9][0-9];do

(

cd $p

for f in [0-9][0-9][0-9][0-9]*.txt;do

ls $f; # Your operands

done

)

done

您需要再次更改备份目录,或者在子shell中执行cd。

谢谢您的纠正,马克。 Subshel??l非常适合这里。

Downvote:编辑丢失了cd,因此此代码实际上没有做任何有用的事情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您可以使用 shell 脚本来实现这个功能。可以先使用 find 命令找出文件中的文件,再使用 stat 命令获取文件的上传时间。最后,可以使用 mv 命令将文件移动到指定目录。 以下是一个示例脚本: ``` #!/bin/bash src_dir=/path/to/src_dir dst_dir=/path/to/dst_dir for file in $(find $src_dir -type f) do upload_time=$(stat -c %y $file | awk '{print $1}') if [ "$upload_time" == "2022-01-01" ]; then mv $file $dst_dir fi done ``` 该脚本首先将源文件中的文件名保存到变量 `file` 中,然后使用 stat 命令获取上传时间并保存到变量 `upload_time` 中。如果文件的上传时间为 2022-01-01,则使用 mv 命令将文件移动到目标目录。 您可以根据需要调整该脚本。 ### 回答2: 实现这个功能,可以使用Linux中的crontab和shell脚本。 首先,你需要编写一个Shell脚本,可以使用任何喜欢的文本编辑器创建一个新文件,比如"move_files.sh"。 ``` #!/bin/bash # 指定源文件路径 source_dir="/path/to/source_folder" # 指定目标文件路径 target_dir="/path/to/target_folder" # 获取源文件中的所有文件 files=$(ls $source_dir) # 遍历每个文件 for file in $files do # 获取当前文件的上传时间 upload_time=$(stat -c %Y $source_dir/$file) # 获取当前时间 current_time=$(date +%s) # 计算时间差(以秒为单位) time_diff=$((current_time - upload_time)) # 如果时间差超过指定的阈值,移动文件到目标文件 if [ $time_diff -ge 3600 ]; then mv $source_dir/$file $target_dir fi done ``` 上述脚本会将源文件中超过一个小时未上传的文件移动到指定的目标文件。 然后,为了实现定时运行该脚本,可以通过crontab创建一个定时任务。在终端中执行以下命令打开crontab编辑器: ``` crontab -e ``` 在编辑器中,添加以下一行来设置定时任务: ``` * * * * * /bin/bash /path/to/move_files.sh ``` 这将每分钟执行一次脚本,你可以根据自己的需要调整时间间隔。 保存并退出编辑器,cron会根据你的设定自动运行移动文件的脚本,并定时获取文件的上传时间并移动文件到指定目录。 ### 回答3: 为了实现定时获取某个文件里文件的上传时间并移动文件到指定目录,我们可以使用Linux下的crontab来实现自动定时执行脚本。 首先,创建一个名为"file_move.sh"的脚本文件,内容如下: ```bash #!/bin/bash # 设置源文件和目标文件的路径 source_dir="/path/to/source_folder" target_dir="/path/to/target_folder" # 遍历源文件里的所有文件 for file in $source_dir/*; do # 获取文件的上传时间 upload_time=$(stat -c %Y "$file") # 获取当前时间 current_time=$(date +%s) # 计算时间差,以秒为单位 time_diff=$((current_time - upload_time)) # 如果文件在规定时间内上传,则将其移动到目标文件 if (($time_diff < 3600)); then mv "$file" "$target_dir" fi done ``` 在脚本中,我们首先设置了源文件和目标文件的路径。然后,利用一个for循环遍历源文件里的所有文件。通过使用"stat -c %Y"命令获取每个文件的上传时间,并获取当前时间。接着,我们计算出二者之差,以秒为单位。如果文件在规定时间内上传(这里设置为1个小时),则利用mv命令将其移动到目标文件。 保存脚本文件并赋予执行权限:chmod +x file_move.sh。 接下来,使用crontab创建一个定时任务。通过运行crontab -e命令打开定时任务编辑器,然后在文件末尾添加以下内容: ``` * * * * * /path/to/file_move.sh ``` 以上命令表示每分钟执行一次脚本。 保存并退出编辑器。现在脚本将会在每分钟检查源文件里的文件上传时间,并将满足条件的文件移动到目标文件中。 请根据实际情况修改脚本中的源文件和目标文件路径以及时间阈值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值