cp в многострочном режиме

В питоне можно сделать

from subprocess import *

def main():
    for i in range(90, 110):
       try :
          url = "url/"+str(i)
          check_output(["wget", url])
       except CalledProcessError:
          print "Wget returned none zero output, quiting"
          sys.exit(0)

Ознакомьтесь с документацией для подпроцесса, если хотите узнать большеhttps://docs.python.org/2/library/subprocess.html

0
17.08.2019, 17:24
2 ответа
files=(
    file1 file2 "the goose incident.png"
    "another file"
    file3 file-4 "fifth file" file6
    "this is file7 with a
newline in the middle of the name" )

cd ~/dir1 &&
cp "${files[@]}" ~/dir2

Это скопирует имена, упомянутые в списке files, из ~/dir1в ~/dir2.

Новые строки между элементами в списке filesне важны, за исключением новой строки в последнем элементе, который представляет собой имя файла с внедренной в него новой строкой (просто для того, чтобы показать, что вы также можете иметь их, без вопросов ).

Список можно было бы и написать

files=(
    file1
    file2
    "the goose incident.png"
    "another file"
    file3
    file-4
    "fifth file"
    file6
    "this is file7 with a
newline in the middle of the name"
)

или как

files=( file1 file2 "the goose incident.png" "another file" file3 file-4
        "fifth file" file6 "this is file7 with a
newline in the middle of the name" )
2
28.01.2020, 02:29

Как насчет этого:

#!/usr/bin/env bash

files="1
2
3
4
4
5
6
7
8
9 10 11"

IFS=$'\n'
for file in $files
do
    touch "$file"
done

Просто замените touch "$file"тем, что вам нужно. То недостатком этого решения является то, что оно будет разветвлять новый процесс для каждый файл, как вы можете видеть с straceи, таким образом, будет медленным для большое количество файлов:

$ strace -f./cp-here-doc.sh  |& grep 'execve("/usr/bin/touch"'
[pid 17917] execve("/usr/bin/touch", ["touch", "1"], [/* 63 vars */]) = 0
[pid 17918] execve("/usr/bin/touch", ["touch", "2"], [/* 63 vars */]) = 0
[pid 17919] execve("/usr/bin/touch", ["touch", "3"], [/* 63 vars */]) = 0
[pid 17920] execve("/usr/bin/touch", ["touch", "4"], [/* 63 vars */]) = 0
[pid 17921] execve("/usr/bin/touch", ["touch", "4"], [/* 63 vars */]) = 0
[pid 17922] execve("/usr/bin/touch", ["touch", "5"], [/* 63 vars */]) = 0
[pid 17923] execve("/usr/bin/touch", ["touch", "6"], [/* 63 vars */]) = 0
[pid 17924] execve("/usr/bin/touch", ["touch", "7"], [/* 63 vars */]) = 0
[pid 17925] execve("/usr/bin/touch", ["touch", "8"], [/* 63 vars */]) = 0
[pid 17926] execve("/usr/bin/touch", ["touch", "9 10 11"], [/* 63 vars */]) = 0

Вы можете использовать xargsдля запуска touchили cpтолько в окончательном сценарии. один раз и заставить скрипт работать быстрее:

#!/usr/bin/env bash

files="1
2
3
4
4
5
6
7
8
9 10 11"

echo "$files" | tr '\n' '\0'  | xargs -0 touch

Результат:

$ strace -f./cp-here-doc.sh  |& grep 'execve("/usr/bin/touch"'
[pid 18290] execve("/usr/bin/touch", ["touch", "1", "2", "3", "4", "4", "5", "6", "7", "8", "9 10 11"], [/* 63 vars */]) = 0

Также обратите внимание, что в Linux по крайней мере имена файлов могут содержать новые строки, поэтому вам нужно выбрать другой разделитель, если хотя бы одно из ваших имен файлов содержит новую строку.

ОП спросил:

what does IFS=$'\n' mean

Это буквально означает новую строку. Вы можете прочитать об этомman bash:

   Words of the form $'string' are treated specially.  The word
   expands to string, with backslash-escaped char- acters replaced
   as specified by the ANSI C standard.  Backslash escape
   sequences, if present, are decoded as follows:
          \a     alert (bell)
          \b     backspace
          \e
          \E     an escape character
          \f     form feed
          \n     new line

Ваш окончательный сценарий может выглядеть так:

#!/usr/bin/env bash

files="1
2
3
4
5
6
7
8
9 10 11"

echo "$files" | tr '\n' '\0'  | xargs -0 cp -t {} dir

Я бы выбрал вариант xargs, так как он намного быстрее и безопаснее -см. комментарий Кусалананды ниже. я не бежал тесты с помощью команды cp, но когда я протестировал touchдля создания файлов в список $(seq 1 1000000)потребовалось всего 16 секунд для xargsэто, но для версии с циклом for потребовалось целых 42 минуты. Также, к моему удивлению xargsсмог разбить список аргументов на несколько команды, так что Argument list too longне будет проблемой.

0
28.01.2020, 02:29

Теги

Похожие вопросы