Linux - How to add incremental numbers to the middle of a filename? [closed] - linux

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I've been seeing a ton of answers that show how to add to the beginning or end of a file, but I'm looking to replace numbers in the middle of a file. I have, for example:
ShowName - S00E01 - Episode Name.mkv
ShowName - S00E02 - Episode Name.mkv
ShowName - S00E03 - Episode Name.mkv
I want to change the E01-E03 part to be something like E20 to E22, or similar, without modifying the rest of the filename.
Couldn't figure out how to do this using linux's "rename" call, any other suggestions?

Linux utility rename is just a simple tool. A more advanced tool using a regular expression is perl-rename, which usually installed separately. However it still will not solve your problem.
For anything more complicated, i usually resort to writing a small bash for loop.
E.g. this script should work for your problem:
# for every file ending with .mkv
for f in *.mkv; do
# transform the filename using sed, so that character '|' character will separate episode number from the lest of the filename (so it can be extracted)
# e.g.
# 'ShowName - S00E01 - Episode Name.mkv' will be
# 'ShowName - S00E|01| - Episode Name.mkv'
# Then read such string to three variables:
# prefix enum and suffix splitting on '|' character
IFS='|' read -r prefix enum suffix < <(sed 's/\(.*S[0-9][0-9]E\)\([0-9][0-9]\)\(.*\)/\1|\2|\3/' <<<"$f");
# newfilename consist of prefix, calculated episode number and the rest of the filename
# i assumed you want to add 19 to episode number
# it may be also a good idea to move files to another directory, to avoid unintentional overwriting of existing files
# you may also consider using -n/--no-clobber or --backup options to mv
newf="another_directory/${prefix}$(printf "%02d" "$((enum-1+20))")${suffix}"
# move "$f" to "$newf"
# filenames have special characters (spaces), so remember about qoutes
echo "'$f' -> '$newf'"
mv -v "$f" "$newf"
done

Use some other tools like grep to help you:
for f in *.mkv; do
NUM=$(echo "$f" | grep -Po '(?<=E)[0-9]{2}')
NEWNUM=$((NUM+20))
fn=${f/E${NUM}/E${NEWNUM}}
mv "$f" "$fn"
done
The rest should be easily done with shell's builtin string replacement functionality.

Related

print multiple words in specific pattern [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have a file word.txt
$ cat word.txt
cat
dog
rat
bird
I have a URL like this
https://example.com/?word=
I want to generate a URL list like this
https://example.com/?word=cat
https://example.com/?word=cat,dog
https://example.com/?word=cat,dog,rat
https://example.com/?word=cat,dog,rat,bird
I have 177 words so how can I automate this process with Bash or any other easy programming
Read the input line by line, add the line to the URL. Don't include the comma for the first line.
#! /bin/bash
url='https://example.com/?word='
while read -r line ; do
url+=$comma$line
comma=,
echo "$url"
done < word.txt
This task can be accomplished with a single GNU sed command:
sed -n 's|^|https://example.com/?word=|; :a; p; N; s/\n/,/; ba' word.txt
That should be more efficient than the plain bash.
Explanation:
-n   With this option, sed only produces output when explicitly told to via the p command.
s|^|https://example.com/?word=|   Replaces the beginning of the line with the https://example.com/?word=. This command effectively prepends that string to the pattern space.
:a   Label a for branch command (b). Used when looping through the lines.
p   Prints the pattern space.
N   Adds a newline to the pattern space, then appends the next line of input to the pattern space.
s/\n/,/   Replaces the newline with the comma (,).
ba   Jumps to the label a. This effectively creates a loop for all input lines except the first line.
Another variant:
url='https://example.com/?word='
while read word; do
words+=($word) list="${words[#]}"
printf '%s%s\n' "$url" ${list// /,}
done < word.txt
You can use something like this if you want to do it in python
words=["a","b","c"]
joinedWords = ",".join(words)
url="https://example.com/?word="
print(url,joinedWords)
reqUrl = url+joinedWords
print(reqUrl)

How can i search for an hexadecimal content in a file in a linux/unix/bash script? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have an hexadecimal string s and a file f, i need to search the first occurence of that string in the file and save that in a variable with his offset. I thought that the right way to do that is convert the file to hex and search that with a grep. The main problem is that i saw a lot of commands(hexdump,xxd,etc.) to convert but none of them actually work. Any suggestion?
My attempt was like this:
xxd -plain $f > $f
grep "$s" .
output should be like:
> offset:filename
A first approach without any error handling could look like
#!/bin/bash
BINFILE=$1
SEARCHSTRING=$2
HEXSTRING=$(xxd -p ${BINFILE} | tr -d "\n")
echo "${HEXSTRING}"
echo "Searching ${SEARCHSTRING}"
OFFSET=$(grep -aob ${SEARCHSTRING} <<< ${HEXSTRING} | cut -d ":" -f 1)
echo ${OFFSET}:${BINFILE}
I've used xxd here because of Does hexdump respect the endianness of its system?. Please take also note that according How to find a position of a character using grep? grep will return multiple matches, not only the first one. The offset will be counted beginning from 1, not 0. To substract 1 from the variable ${OFFSET} you may use $((${OFFSET}-1)).
I.e. search for the "string" ELF (HEX 454c46) in a system binary will look like
./searchHEX.sh /bin/yes 454c46
7f454c460201010000000000000000000...01000000000000000000000000000000
Searching 454c46
2:/bin/yes
I would use regex for this as well:
The text file:
$ cat tst.txt
1234567890x1fgg0x1cfffrr
A script you can easily change/extend yourself.
#! /bin/bash
part="$(perl -0pe 's/^((?:(?!0(x|X)[0-9a-fA-F]+).)*)(0(x|X)[0-9a-fA-F]+)(.|\n)*/\1:\3\n/g;' tst.txt)"
tmp=${part/:0x*/}
tmp=${#tmp}
echo ${part/*:0x/$tmp:0x} # Echoes 123456789:0x1f
Regex:
^((?:(?!0x[0-9a-fA-F]+).)*) = Search for the first entry that's a hexadecimal number and create a group of it (\1).
(0x[0-9a-fA-F]+) = Make a group of the hexadecimal number (\3).
(.|\n)* = Whatever follows.
Please note that tmp=${part/:0x*/} could cause problems if you have text like :0x before the hexadecimal number that is caught.

Create mutiple files in multiple directories [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I 've got tree of folders like:
00 -- 0
-- 1
...
-- 9
...
99 -- 0
-- 1
...
-- 9
How is the simplest way to create in every single subfolders a file like:
/00/0/00_0.txt
and save to every files some kind of data?
I tried with touch and with loop but without success.
Any ideas how to make it very simple?
List all directories using globs. Modify the listed paths with sed so that 37/4 becomes 37/4/37_4.txt. Use touch to create empty files for all modified paths.
touch $(printf %s\\n */*/ | sed -E 's|(.*)/(.*)/|&\1_\2.txt|')
This works even if 12/3 was just a placeholder and your actual paths are something like abcdef/123. However it will fail when your paths contain any special symbols like whitespaces, *, or ?.
To handle arbitrary path names use the following command. It even supports linebreaks in path names.
mapfile -td '' a < <(printf %s\\0 */*/ | sed -Ez 's|(.*)/(.*)/|&\1_\2.txt|')
touch "${a[#]}"
You may use find and then run commands using -exec
find . -type d -maxdepth 2 -mindepth 2 -exec bash -c 'f={};
cmd=$(echo "${f}/${f%/*}_${f##*/}.txt"); touch $cmd' \;
the bash substitution ${f%/*}_${f##*/} replaces the last / with _

Link separated words [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
I would know if there is a program or a script that can link separated words in a file name with a dot (or other punctuation marks).
Example:
How are you.pdf >>> How.are.you.pdf
I did not explain myself well, I'm looking for a bash script that can rename file names
Assuming you have How are you.pdf in a variable you can use parameter expansions:
% a="How are you.pdf"
% echo "${a// /.}"
How.are.you.pdf
The above is a bash expansion and doesn't work in a POSIX shell. In that case sed or simulare would be needed.
To rename all files in the current directory:
for a in *; do
[ -f "$a" ] || continue
mv -- "$a" "${a// /.}"
done
sed is your help here.
For example:
echo "How are you.pdf" | sed 's/ /./g'
The sed command is divided to command/1st argument/2nd argument/command
In our example:
s - search
[space] - the space character
. - the dot character to
replace
g - do this globally and not only for the first occurrence
There is a tool called perl-rename sometimes called rename - not to be confused with rename from util-linux.
This tool take a Perl expressions and renames accordingly:
perl-rename 's/ /./g' *
The above will rename all files / directories in the current directory to add replace spaces for periods:
How are you.pdf -> How.are.you.pdf
This is another.file -> This.is.another.file
You can try the regex online

How do I create a bash file that creates a symbolic link (linux) for each file moved from Folder A to Folder B [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
How do I create a bash file that creates a symbolic link (linux) for each file moved from Folder A to Folder B.
However, this would be done selecting the 150 biggest current files from Folder A.
Can probably write it in a one liner, but easier in a simple bash script like
#!/bin/bash
FolderA="/some/folder/to/copy/from/"
FolderB="/some/folder/to/copy/to/"
while read -r size file; do
mv -iv "$file" "$FolderB"
ln -s "${FolderB}${file##*/}" "$file"
done < <(find "$FolderA" -maxdepth 1 -type f -printf '%s %p\n'| sort -rn | head -n150)
Note ${file##*/} removes everything before the last /, per
${parameter##word}
Remove matching prefix pattern. The word is expanded to produce a pattern just as in pathname expansion. If the
pattern matches the beginning of the value of parameter, then the result of the expansion is the expanded value of
parameter with the shortest matching pattern (the ``#'' case) or the longest matching pattern (the ``##'' case)
deleted. If parameter is # or *, the pattern removal operation is applied to each positional parameter in turn, and
the expansion is the resultant list. If parameter is an array variable subscripted with # or *, the pattern removal
operation is applied to each member of the array in turn, and the expansion is the resultant list.
Also, it may seem like a good idea to just do for file in $(command), but process substitution and while/read works better in general to avoid word-splitting issues like splitting up files with spaces, etc...
As with any task, break it up into smaller pieces, and things will fall into place.
Select the biggest 150 files from FolderA
This can be done with du, sort, and awk, the output of which you stuff into an array:
du -h /path/to/FolderA/* | sort -h | head -n150 | awk '{print $2}'
Move files from FolderA into FolderB
Take the list from the last command, and iterate through it:
for file in ${myarray[#]}; do mv "$file" /path/to/FolderB/; done
Make a symlink to the new location
Again, just iterate through the list:
for file in ${myarray[#]; do ln -s "$file" "/path/to/FolderB/${file/*FolderA\/}"; done

Resources