Linux 如何将包含目录作为前缀添加到复制的文件名中?

Linux 如何将包含目录作为前缀添加到复制的文件名中?,linux,bash,shell,cp,Linux,Bash,Shell,Cp,问题:我有一堆文件被分割到多个目录中,它们都有相同的名称(input.txt) 我的目标:我想首先将所有这些内容复制到一个新目录,同时将包含的目录添加为suffux,以避免它们之间的混淆并防止覆盖。这是我试图做的工作的基础: cp -nr /foo/bar/*/input.txt /new/path/ 我该怎么办 如果/old/目录中的我的文件结构包含文件夹,请响应以下注释: /old/directory/1/input.txt /old/directory/2/input.txt /old/

问题:我有一堆文件被分割到多个目录中,它们都有相同的名称(input.txt)

我的目标:我想首先将所有这些内容复制到一个新目录,同时将包含的目录添加为suffux,以避免它们之间的混淆并防止覆盖。这是我试图做的工作的基础:

cp -nr /foo/bar/*/input.txt /new/path/
我该怎么办

如果/old/目录中的我的文件结构包含文件夹,请响应以下注释:

/old/directory/1/input.txt
/old/directory/2/input.txt
/old/directory/3/input.txt
这是我所需输出的一个示例: /新的/directory/应包含:

1input.txt
2input.txt
3input.txt

谢谢

好吧,不幸的是,没有一种明显的方式可以在一行中做到这一点,也没有一种方式不难理解。也许有一种方法可以用rsync实现,我相信比我更聪明的人可以用awk实现,但在我看来,你最好编写一个脚本,甚至编写一个自定义二进制文件来实现这一点

find . -name input.txt | while read line
do
    cp "$line" /new/path/`echo $line | cut -d '/' -f3- | sed 's/\//_/'`
done

请注意,您可能必须更改cut命令的-f3-部分,以便选择要以哪个目录名作为后缀开头。

好吧,最糟糕的是,没有一种明显的方式在一行中执行此操作,而不是一种不难理解的方式。也许有一种方法可以用rsync实现,我相信比我更聪明的人可以用awk实现,但在我看来,你最好编写一个脚本,甚至编写一个自定义二进制文件来实现这一点

find . -name input.txt | while read line
do
    cp "$line" /new/path/`echo $line | cut -d '/' -f3- | sed 's/\//_/'`
done

请注意,您可能必须更改cut命令的-f3-部分,以便选择要以哪个目录名开始后缀。

一种方法是使用数组保存文件,而且由于文件名上不允许使用
/
,另一种方法是将其更改为其他名称,如下划线

#/usr/bin/env bash
##:仅在没有文件/目录的情况下,*glob不会自行展开。
shopt-s nullglob
files=(foo/bar/*/input.txt)
对于“${files[@]}”中的文件;做
new_file=${file/\/\/\}\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
echo cp-v“$file”new/path/“$new_文件”
完成

根据OP的要求,这里是新的答案

#/usr/bin/env bash
shopt-s nullglob
##:尽管文件=(/old/directory/{1..3}/input.txt)
##:可以替换,不需要nullglob
files=(/old/directory/*/input.txt)
对于“${files[@]}”中的文件;做
tmp=${file%[0-9]*}
新建文件=${file#*$tmp}
echo cp-v“$file”new/path/“${new\u file//\/}”
完成

另一个选项是使用
/
作为分隔符拆分字段

#/usr/bin/env bash
##:如果没有文件/目录,请不要展开文本glob*
shopt-s nullglob
##:将整个路径和文件保存在数组中。
files=(/old/directory/*/input.txt)
对于“${files[@]}”中的文件;做

如果s='/'read-ra path一种方法是使用数组保存文件,而且由于文件名上不允许使用
/
,另一种方法是将其更改为其他内容,例如下划线

#/usr/bin/env bash
##:仅在没有文件/目录的情况下,*glob不会自行展开。
shopt-s nullglob
files=(foo/bar/*/input.txt)
对于“${files[@]}”中的文件;做
new_file=${file/\/\/\}\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
echo cp-v“$file”new/path/“$new_文件”
完成

根据OP的要求,这里是新的答案

#/usr/bin/env bash
shopt-s nullglob
##:尽管文件=(/old/directory/{1..3}/input.txt)
##:可以替换,不需要nullglob
files=(/old/directory/*/input.txt)
对于“${files[@]}”中的文件;做
tmp=${file%[0-9]*}
新建文件=${file#*$tmp}
echo cp-v“$file”new/path/“${new\u file//\/}”
完成

另一个选项是使用
/
作为分隔符拆分字段

#/usr/bin/env bash
##:如果没有文件/目录,请不要展开文本glob*
shopt-s nullglob
##:将整个路径和文件保存在数组中。
files=(/old/directory/*/input.txt)
对于“${files[@]}”中的文件;做

IFS='/'read-ra path这将实现这一技巧,并处理名称中可能包含空格(或任何其他奇数字符)的任何目录


这将实现这一技巧,还可以处理名称中可能包含空格(或任何其他奇数字符)的任何目录


不完全是吗?我想将所有文件移到同一个文件夹中。这似乎是将整个目录结构复制到新位置,还是我做错了?啊,不,我误解了-你是对的。我想你的意思是你想要整个目录结构。我将编辑我的答案。当我这样做时,我会得到以下错误:
find:warning:Unix文件名通常不包含斜杠(虽然路径名包含斜杠)。
另外:
find:path必须在表达式前面:
/new/path/input.txt'`和
find:predicate
-name'后面可能有无引号的模式?`不完全?我想将所有文件移到同一个文件夹中。这似乎是将整个目录结构复制到新位置,还是我做错了?啊,不,我误解了-你是对的。我想你的意思是你想要整个目录结构。我将编辑我的答案。执行此操作时,会出现以下错误:
find:警告:Unix文件名通常不包含斜杠(尽管路径名包含斜杠).
另外:
find:path必须在表达式之前:
/new/path/input.txt'`和
find:predicate之后可能有无引号的模式
-name'?`请通过给出示例输入文件名和所需的输出文件名来澄清“将包含目录作为后缀添加”的含义。我现在正在回答问题。请通过给出示例输入文件名和所需输出来澄清“添加包含目录作为后缀”的含义。我现在正在回答问题。好吧,这真的很接近我想要的!我想这会打印出整个路径
$ tree ./old/directory/
./old/directory/
├── 1
│   └── input.txt
├── 2
│   └── input.txt
└── 3
    ├── 3a
    │   └── input.txt
    └── input.txt

4 directories, 4 files


$ ./mvinput.sh
cp ./old/directory/3/input.txt ./new/directory/3input.txt
cp ./old/directory/3/3a/input.txt ./new/directory/33ainput.txt
cp ./old/directory/1/input.txt ./new/directory/1input.txt
cp ./old/directory/2/input.txt ./new/directory/2input.txt