How do I truncate the last two characters of all files in a directory? [duplicate] - bash

This question already has answers here:
Bash script to remove 'x' amount of characters the end of multiple filenames in a directory?
(3 answers)
Closed 5 years ago.
So pretty simple question. All of the files in my directory are of the form 6bfefb348d746eca288c6d62f6ebec04_0.jpg. I want them to look like 6bfefb348d746eca288c6d62f6ebec04.jpg. Essentially, I want to take off the _0 at the end of every file name. How would I go about doing this with bash?

With Perl's standalone rename command:
rename -n 's/..(\....)$/$1/' *
If everything looks fine, remove -n.
It is possible to use this standalone rename command with a syntax similar to sed's s/regexp/replacement/ command. In regex a . matches one character. \. matches a . and $ matches end of line (here end of filename). ( and ) are special characters in regex to mark a subexpression (here one . and three characters at the end of your filename) which then can be reused with $1. sed uses \1 for first back-reference, rename uses $1.
See: Back-references and Subexpressions with sed

Related

What does ${i%.*} do in this context? [duplicate]

This question already has answers here:
What does the curly-brace syntax ${var%.*} mean?
(3 answers)
Closed 2 years ago.
I'm learning a bit about running a bash script in a linux terminal, specifically in the context of converting audio video files.
I came across this command here on SO that does exactly what I want. However, I'd like to understand it better:
for i in *.avi; do ffmpeg -i "$i" "${i%.*}.mp4"; done
Now, this is obviously a for-loop and I get the first * wildcard. I get the do block. But what I don't quite understand is ${i%.*}. Specifically, what does the %.* bit do in the output location? Why not use ${i}.mp4 instead?
It's called parameter expansion and it removes everything starting from the last dot (ie. extension). Try the following:
$ i="foo.bar.baz"
$ echo ${i%.*}
foo.bar
Author of the original code ("${i%.*}.mp4") apparently wanted to replace original extension with .mp4 so the original extension is removed and .mp4 is appended.
Parameter expansion
${parameter%word}
${parameter%%word}
The word is expanded to produce a pattern and matched according to the rules described below (see Pattern Matching). If the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is the value of parameter with the shortest matching pattern (the ‘%’ case) or the longest matching pattern (the ‘%%’ case) deleted.

How to replace quotes inside a quoted field of a non-standard CSV file using a one-liner bash command? [duplicate]

This question already has answers here:
What's the most robust way to efficiently parse CSV using awk?
(6 answers)
Closed 4 years ago.
This post was edited and submitted for review 11 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have a file like this:
col1×col2×col3
12×"Some field with "quotes" inside it"×"Some field without quotes inside but with new lines \n"
And I would like to replace the interior double quotes with single quotes so the result will look like this:
col1×col2×col3
12×"Some field with 'quotes' inside it"×"Some field without quotes inside but with new lines \n"
I guess this can be done with sed, awk or ex but I haven't been able to figure out a clean and quick way of doing it. Real CSV files are of the order of millions of lines.
The preferred solution would be a one-liner using the aforementioned programs.
A simple workaround using sed, based on your fields separator ×, could be:
sed -E "s/([^×])\"([^×])/\1'\2/g" file
This replace each " which is preceded and followed by any characters other that ×, with '.
Note that sed not support positive lookahead, so we have to group and reinsert the patterns.

UNIX Replace string without replacing space [duplicate]

This question already has answers here:
I just assigned a variable, but echo $variable shows something else
(7 answers)
Closed 5 years ago.
For string matching purposes I need to define a bash variable with leading spaces.
I need to define this starting from an integer, like:
jj=5
printf seems to me a good idea, so if I want to fill spaces up to 6 character:
jpat=`printf " %6i" $jj`
but unluckly when I am trying to recall the variable:
echo $jpat
the leading whitespaces are removed and I only get the $jj integer as it was.
Any solution to keep such spaces?
(This is equivalent to this: v=' val'; echo $v$v. Why aren't there leading and multiple spaces in output?)
Use More Quotes! echo "$jpat" will do what you want.
There is another issue with what you're doing: Command substitutions will remove trailing newlines. It's not an issue in the printf command you're using, but for example assigning jpat=$(printf " %6i\n" "$jj") would give you exactly the same result as your command.

What is a `##` means in bash variable substitution `${}`? [duplicate]

This question already has answers here:
What is the meaning of the ${0##...} syntax with variable, braces and hash character in bash?
(4 answers)
Closed 2 years ago.
I am learning the bash script materials on http://www.tldp.org/LDP/abs/html/index.html
and stuck in the Example 7-7:
http://tldp.org/LDP/abs/html/comparison-ops.html#EX14
There is an ${filename##*.} != "gz", this probably means
that the $filename does not end with .gz, but I do not
know the meaning of ## here. Could anyone help me?
Thanks!
Used in a variable expansion, ${string##sub} removes the longest matching substring sub from string (# removes the shortest matching substring by contrast).
In your case, yes - this will return the string after the first . from the filename, giving the file extension.
If you search for ## in this documentation, you'll find an explanation (along with other similar commands).
In the context of filenames, is trying to find the extension in the variable filename
filename="*.log"
echo ${filename##*.}
log
We are attaining the part of the string filename after "*."
## is a used for to remove a substring from a variable. For more info check this page.
For eg. if filename=/home/user.name/folder.1/test.gz, then ${filename##*.} will give you output as gz.

Extended glob can't retrace behaviour

I looked at a bash guide where I found this example:
http://guide.bash.academy/expansions/
$ ls !(my*).txt # All the .txt files that do not begin with my.
hello.txt
$ ls !(my)*.txt # Can you guess why this one matches myscript.txt?
myscript.txt
hello.txt
I'm familiar with basic concepts of regular expressions maybe this is confusing me because I'm trying to apply those concepts to extended globs in bash.
I do not understand why !(my)*.txt is expanding myscript.txt in bash. The explanation in the guide does not help me at all.
My reasoning:
!(my*).txt does not match myscript.txt because it does start with my then matches the rest of the characters script and at the end it matches .txt
!(my)*.txt does not (wrong!!!) match myscript.txt because it is starting with my followed by any characters and at the end it matches .txt
Where am I wrong in my argumentation?
This is a common gotcha with wildcards. The question to ask yourself is, is there any way to split up myscript.txt such that the first piece matches !(my) and the second matches *.txt?
The answer is, counter-intuitively, yes: If you "split" "myscript.txt" into "" (the empty string) and "myscript.txt" then the empty string matches !(my) and "myscript.txt" matches *.txt. The empty string is a valid match!

Resources