如何在 shell 脚本中迭代两组可迭代对象?

如何在 shell 脚本中迭代两组可迭代对象?

通常,当我为特定任务编写 shell 脚本时,我只是创建一个文件列表,如下所示:

#/bin/sh
read -d '' imagefiles <<EOF

./01/IMG0000.jpg
./01/IMG0001.jpg
./01/IMG0002.jpg
./01/IMG0003.jpg
./01/IMG0004.jpg
./01/IMG0005.jpg
./01/IMG0006.jpg
./01/IMG0007.jpg
(a whole bunch of files down to ./10/IMG0102.jpg)

EOF

for i in $imagefiles
  for j in range(len(commands))
do

mv $i ./$j.jpg

  done
done

在本例中,我希望能够迭代 的输出seq,但按照 Gilles 的建议,只需将这部分写为 Python(是的,我知道它会执行每个命令 j 次,导致大约 100000 次执行) 。当天早些时候,我按顺序重命名了 736 个文件,但现在我要重命名 1000 多个文件。我确信有更好的方法可以做到这一点(请毫不犹豫地告诉我),但是知道如何迭代命令列表和其他一些可迭代的内容仍然会很高兴。

答案1

好的,所以您想要压缩两个可迭代对象,或者换句话说,您想要一个循环,迭代一堆字符串,并带有一个附加计数器。实现计数器非常容易。

n=0
for x in $commands; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done

请注意,只有当您要迭代的元素都不包含任何空格(也不包含通配符)时,这才有效。如果您的项目由换行符分隔,请关闭通配符并仅在换行符上拆分。

n=0
IFS='
'; set -f
for x in $commands; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done
set +f; unset IFS

如果您只需要迭代数据一次,请循环read(请参阅为什么while IFS= read如此频繁地使用而不是IFS=; while read..以获得更多解释)。

n=0
while IFS= read -r x; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done <<EOF
EOF

如果您使用的 shell 具有数组(bash、ksh 或 zsh),请将元素存储在数组中。在 zsh 中,要么运行setopt ksh_arrays从 0 开始对数组元素进行编号,要么调整代码以从 1 开始对数组元素进行编号。

commands=(
    ./01/IMG0000.jpg
)
n=0
while [[ $n -lt ${#commands} ]]; do
  mv -- "${commands[$n]}" "$n.jpg"
done

答案2

如果您的 shell 是bash,则无需运行该seq程序。只需使用

for i in {1..736}
  do

如果您想要一个带有前导零的序列,只需使用{001..736}(甚至{0001..0736}) 即可。

另外,如果可能的话,尽量不要使用反引号(请参阅这个问题,了解它如何把事情搞砸)。

另一件事是,当您想要操作一组文件时,您可能会发现这很有用:

for file in /some/path/*
  do

它将对所有文件进行操作(和文件夹)在目录中/some/path/。要将范围缩小到仅文件,您可以使用类似的测试[ -f "$file" ],例如

for file in /some/path/*
  do
  [ -f "$file" ] || continue
  (do your stuff here)

此外,该构造可以通过、等/some/path/*shell 模式进行调整。/some/path[123]/*/some/path[A-Z]/b*[e-g]*/some/path{1,5,23}/*

就问题的第一部分而言,您可以使用嵌套for(或while任何)循环,如下所示:

for cm in $commands; do
 for file in /some/path[ab]{1,4,2}/*.log; do
    mv "${file}" "${file//text/replacement}"
 done
done

答案3

我不认为你可以在 bash 中并行迭代多个事物。

我会开始i=1。然后迭代文件列表并包含let i=$i+1在循环中。$i -ge 736如果您想在循环次数之后停止对输入的任何内容进行迭代,还包括一个跳出循环的测试。

i=0
for file in ./{01..10}/*jpg; do
    let i=$i+1
    mv "$file" "$i-$file"
done

如果您尝试关闭 X 个文件,您可以使用如下测试:

[[ $i -ge 736 ]] && return || let i=$i+1

答案4

bash 支持数组:

http://tldp.org/LDP/abs/html/arrays.html

或者

COUNT=0
for i in `ls *.txt`
do
  COUNT=`expr $COUNT + 1`
  mv "$i" "$COUNT-$i"
done

这会将文件 a.txt b.txt c.txt 重命名为 1-a.txt 2-b.txt 3-c.txt。

相关内容