- How to loop over files in directory and change path and add suffix to filename
- 6 Answers 6
- Оберните струны
- Цикл по диапазону чисел
- Перебирать элементы массива
- Цикл for в Bash в стиле C
- Операторы break и continue
- Оператор break
- Оператор continue
- Примеров циклов for в Bash
- Переименование файлов с пробелами в имени файла
- Изменение расширения файла
- Выводы
- For files in directory, only echo filename (no path)
How to loop over files in directory and change path and add suffix to filename
I need to write a script that starts my program with different arguments. I start my program with: ./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.txt end for end for
How can I create the second argument from the first one, so it looks like dataABCD_Log1.txt and start my program?
@LéaGris The proposed duplicate seems less stellar, especially as one of the answers there still advocates looping over ls output. These seem different enough that I have not nominated that as a duplicate of this, either.
6 Answers 6
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:
#!/bin/bash for filename in /Data/*.txt; do for ((i=0; i
- /Data/*.txt expands to the paths of the text files in /Data (including the /Data/ part)
- $( . ) runs a shell command and inserts its output at that point in the command line
- basename somepath .txt outputs the base part of somepath, with .txt removed from the end (e.g. /Data/file.txt -> file )
If you needed to run MyProgram with Data/file.txt instead of /Data/file.txt , use "$" 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 .
for цикл в Bash
Циклы — одна из фундаментальных концепций языков программирования. Циклы удобны, когда вы хотите запускать серию команд снова и снова, пока не будет достигнуто определенное условие.
В языках сценариев, таких как Bash, циклы полезны для автоматизации повторяющихся задач. В Bash доступны три основные конструкции цикла: for , while и until циклы.
В этом руководстве мы рассмотрим основы циклов for в Bash. Мы также покажем вам, как использовать операторы break и continue чтобы изменить ход цикла.
Стандартный for цикл в Bash
Цикл for выполняет итерацию по списку элементов и выполняет заданный набор команд.
Цикл for Bash имеет следующую форму:
for item in [LIST] do [COMMANDS] done
Список может быть серией строк, разделенных пробелами, диапазоном чисел, выводом команды, массивом и т. Д.
Оберните струны
В приведенном ниже примере цикл будет перебирать каждый элемент в списке строк, и переменный element будет установлен на текущий элемент:
for element in Hydrogen Helium Lithium Beryllium do echo "Element: $element" done
Цикл выдаст следующий результат:
Element: Hydrogen Element: Helium Element: Lithium Element: Beryllium
Цикл по диапазону чисел
Вы можете использовать выражение последовательности, чтобы указать диапазон чисел или символов, задав начальную и конечную точки диапазона. Выражение последовательности принимает следующую форму:
Вот пример цикла, который перебирает все числа от 0 до 3:
for i in 0..3> do echo "Number: $i" done
Number: 0 Number: 1 Number: 2 Number: 3
Начиная с Bash 4, также можно указывать приращение при использовании диапазонов. Выражение принимает следующий вид:
Вот пример, показывающий, как увеличить на 5:
for i in 0..20..5> do echo "Number: $i" done
Number: 0 Number: 5 Number: 10 Number: 15 Number: 20
Перебирать элементы массива
Вы также можете использовать цикл for для перебора массива элементов.
В приведенном ниже примере мы определяем массив с именем BOOKS и перебираем каждый элемент массива.
BOOKS=('In Search of Lost Time' 'Don Quixote' 'Ulysses' 'The Great Gatsby') for book in "$BOOKS[@]>"; do echo "Book: $book" done
Book: In Search of Lost Time Book: Don Quixote Book: Ulysses Book: The Great Gatsby
Цикл for в Bash в стиле C
Синтаксис цикла for стиле C имеет следующий вид:
for ((INITIALIZATION; TEST; STEP)) do [COMMANDS] done
Часть INITIALIZATION выполняется только один раз при запуске цикла. Затем оценивается TEST . Если это ложь, цикл прекращается. Если TEST истинен, команды внутри цикла for выполняются, а часть STEP обновляется.
В следующем примере кода цикл начинается с инициализации i = 0 и перед каждой итерацией проверяется, является ли i ≤ 10 . Если true, он печатает текущее значение i и [увеличивает переменную] i на 1 ( i++ ), в противном случае цикл завершается.
for ((i = 0 ; i = 1000 ; i++)); do echo "Counter: $i" done
Цикл повторится 1001 раз и выдаст следующий результат:
Counter: 0 Counter: 1 Counter: 2 . Counter: 998 Counter: 999 Counter: 1000
Операторы break и continue
Операторы break и continue могут использоваться для управления выполнением цикла for.
Оператор break
Оператор break завершает текущий цикл и передает управление программой оператору, следующему за завершенным оператором. Обычно он используется для завершения цикла при выполнении определенного условия.
В следующем примере мы используем оператор if для прекращения выполнения цикла, когда текущий повторяемый элемент становится равным «Lithium».
for element in Hydrogen Helium Lithium Beryllium; do if [[ "$element" == 'Lithium' ]]; then break fi echo "Element: $element" done echo 'All Done!'
Element: Hydrogen Element: Helium All Done!
Оператор continue
Оператор continue завершает текущую итерацию цикла и передает управление программой следующей итерации цикла.
В следующем примере мы перебираем диапазон чисел. Когда текущий повторяемый элемент равен ‘2’, оператор continue заставит выполнение вернуться к началу цикла и продолжить следующую итерацию:
for i in 1..5>; do if [[ "$i" == '2' ]]; then continue fi echo "Number: $i" done
Number: 1 Number: 3 Number: 4 Number: 5
Примеров циклов for в Bash
Переименование файлов с пробелами в имени файла
В следующем примере показано, как переименовать все файлы в текущем каталоге с пробелом в его именах, заменив пробел на подчеркивание:
for file in * *; do mv "$file" "$file// /_>" done
Давайте разберем код построчно:
- Первая строка создает цикл for и выполняет итерацию по списку всех файлов с пробелом в имени. Выражение * * создает список.
- Вторая строка применяется к каждому элементу списка и перемещает файл в новый, заменяя пробел знаком подчеркивания ( _ ). Часть $ использует расширение параметра оболочки для замены шаблона в параметре строкой.
- done указывает конец сегмента цикла.
Изменение расширения файла
В следующем примере показано, как использовать цикл for в Bash for переименования всех файлов, оканчивающихся на .jpeg, в текущем каталоге путем замены расширения файла с .jpeg на .jpg.
for file in *.jpeg; do mv -- "$file" "$file%.jpeg>.jpg" done
Давайте проанализируем код построчно:
- Первая строка создает цикл for и выполняет итерацию по списку всех файлов, заканчивающихся на ‘.jpeg’.
- Вторая строка применяется к каждому элементу списка и перемещает файл в новый, заменяя «.jpeg» на «.jpg». $ чтобы удалить часть ‘.jpeg’ из имени файла, используя расширение параметра оболочки
- done указывает конец сегмента цикла.
Выводы
Цикл for Bash используется для повторного выполнения заданного набора команд определенное количество раз.
Если у вас есть какие-либо вопросы или отзывы, не стесняйтесь оставлять комментарии.
For files in directory, only echo filename (no path)
The quotes are needed in case $filename contains e.g. spaces.
Sorry for commenting on this old answer, but basename won't work correctly for files with space. Example: pwd output: /test 1 , basename $(pwd) output: test . Tested on OS X and Ubuntu Server (14.04). Native bash solution, as @SiegeX recommended, is what worked for me.
@YoungFrog thanks for the input, but that was 9 months ago. Also it would be better to use the variable $PWD instead of running the command.
echo $(basename /foo/bar/stuff)
Why do you use echo ? basename already prints the results. echo may even mangle the result if you don't quote the subshell. Example: echo $(basename path/with\ \ spaces) incorrectly prints with spaces (only one space).
Another approach is to use ls when reading the file list within a directory so as to give you what you want, i.e. "just the file name/s". As opposed to reading the full file path and then extracting the "file name" component in the body of the for loop.
Example below that follows your original:
for filename in $(ls /home/user/) do echo $filename done;
If you are running the script in the same directory as the files, then it simply becomes:
for filename in $(ls) do echo $filename done;
ls includes any dotfiles where * expansion usually does not. Also for f in $(. ) . fails if any filename contains whitespace unless you set IFS, may fail if any filename contains a glob char unless you set -f/-o noglob, and depending on system or shell echo may fail if any filename is hyphen+letter or contains backslash. OTOH just ls -1 /path/to/dir all by itself reliably prints each filename on a line, modulo the dotfiles difference.
You can either use what SiegeX said above or if you aren't interested in learning/using parameter expansion, you can use:
for filename in $(ls /home/user/); do echo $filename done;